summaryrefslogtreecommitdiff
path: root/platform/android/src/com/artifex/mupdfdemo/ReaderView.java
diff options
context:
space:
mode:
Diffstat (limited to 'platform/android/src/com/artifex/mupdfdemo/ReaderView.java')
-rw-r--r--platform/android/src/com/artifex/mupdfdemo/ReaderView.java936
1 files changed, 0 insertions, 936 deletions
diff --git a/platform/android/src/com/artifex/mupdfdemo/ReaderView.java b/platform/android/src/com/artifex/mupdfdemo/ReaderView.java
deleted file mode 100644
index 65d8f665..00000000
--- a/platform/android/src/com/artifex/mupdfdemo/ReaderView.java
+++ /dev/null
@@ -1,936 +0,0 @@
-package com.artifex.mupdfdemo;
-
-import java.util.LinkedList;
-import java.util.NoSuchElementException;
-
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.AlertDialog;
-import android.content.DialogInterface;
-
-import android.content.Context;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.util.SparseArray;
-import android.view.GestureDetector;
-import android.view.MotionEvent;
-import android.view.ScaleGestureDetector;
-import android.view.View;
-import android.widget.Adapter;
-import android.widget.AdapterView;
-import android.widget.Scroller;
-
-public class ReaderView
- extends AdapterView<Adapter>
- implements GestureDetector.OnGestureListener, ScaleGestureDetector.OnScaleGestureListener, Runnable {
- private static final int MOVING_DIAGONALLY = 0;
- private static final int MOVING_LEFT = 1;
- private static final int MOVING_RIGHT = 2;
- private static final int MOVING_UP = 3;
- private static final int MOVING_DOWN = 4;
-
- private static final int FLING_MARGIN = 100;
- private static final int GAP = 20;
-
- private static final float MIN_SCALE = 1.0f;
- private static final float MAX_SCALE = 5.0f;
- private static final float REFLOW_SCALE_FACTOR = 0.5f;
-
- private static final boolean HORIZONTAL_SCROLLING = true;
-
- private Adapter mAdapter;
- private int mCurrent; // Adapter's index for the current view
- private boolean mResetLayout;
- private final SparseArray<View>
- mChildViews = new SparseArray<View>(3);
- // Shadows the children of the adapter view
- // but with more sensible indexing
- private final LinkedList<View>
- mViewCache = new LinkedList<View>();
- private boolean mUserInteracting; // Whether the user is interacting
- private boolean mScaling; // Whether the user is currently pinch zooming
- private float mScale = 1.0f;
- private int mXScroll; // Scroll amounts recorded from events.
- private int mYScroll; // and then accounted for in onLayout
- private boolean mReflow = false;
- private boolean mReflowChanged = false;
- private final GestureDetector
- mGestureDetector;
- private final ScaleGestureDetector
- mScaleGestureDetector;
- private final Scroller mScroller;
- private final Stepper mStepper;
- private int mScrollerLastX;
- private int mScrollerLastY;
- private float mLastScaleFocusX;
- private float mLastScaleFocusY;
-
- static abstract class ViewMapper {
- abstract void applyToView(View view);
- }
-
- public ReaderView(Context context) {
- super(context);
- mGestureDetector = new GestureDetector(this);
- mScaleGestureDetector = new ScaleGestureDetector(context, this);
- mScroller = new Scroller(context);
- mStepper = new Stepper(this, this);
- }
-
- public ReaderView(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- // "Edit mode" means when the View is being displayed in the Android GUI editor. (this class
- // is instantiated in the IDE, so we need to be a bit careful what we do).
- if (isInEditMode())
- {
- mGestureDetector = null;
- mScaleGestureDetector = null;
- mScroller = null;
- mStepper = null;
- }
- else
- {
- mGestureDetector = new GestureDetector(this);
- mScaleGestureDetector = new ScaleGestureDetector(context, this);
- mScroller = new Scroller(context);
- mStepper = new Stepper(this, this);
- }
- }
-
- public ReaderView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- mGestureDetector = new GestureDetector(this);
- mScaleGestureDetector = new ScaleGestureDetector(context, this);
- mScroller = new Scroller(context);
- mStepper = new Stepper(this, this);
- }
-
- public int getDisplayedViewIndex() {
- return mCurrent;
- }
-
- public void setDisplayedViewIndex(int i) {
- if (0 <= i && i < mAdapter.getCount()) {
- onMoveOffChild(mCurrent);
- mCurrent = i;
- onMoveToChild(i);
- mResetLayout = true;
- requestLayout();
- }
- }
-
- public void moveToNext() {
- View v = mChildViews.get(mCurrent+1);
- if (v != null)
- slideViewOntoScreen(v);
- }
-
- public void moveToPrevious() {
- View v = mChildViews.get(mCurrent-1);
- if (v != null)
- slideViewOntoScreen(v);
- }
-
- // When advancing down the page, we want to advance by about
- // 90% of a screenful. But we'd be happy to advance by between
- // 80% and 95% if it means we hit the bottom in a whole number
- // of steps.
- private int smartAdvanceAmount(int screenHeight, int max) {
- int advance = (int)(screenHeight * 0.9 + 0.5);
- int leftOver = max % advance;
- int steps = max / advance;
- if (leftOver == 0) {
- // We'll make it exactly. No adjustment
- } else if ((float)leftOver / steps <= screenHeight * 0.05) {
- // We can adjust up by less than 5% to make it exact.
- advance += (int)((float)leftOver/steps + 0.5);
- } else {
- int overshoot = advance - leftOver;
- if ((float)overshoot / steps <= screenHeight * 0.1) {
- // We can adjust down by less than 10% to make it exact.
- advance -= (int)((float)overshoot/steps + 0.5);
- }
- }
- if (advance > max)
- advance = max;
- return advance;
- }
-
- public void smartMoveForwards() {
- View v = mChildViews.get(mCurrent);
- if (v == null)
- return;
-
- // The following code works in terms of where the screen is on the views;
- // so for example, if the currentView is at (-100,-100), the visible
- // region would be at (100,100). If the previous page was (2000, 3000) in
- // size, the visible region of the previous page might be (2100 + GAP, 100)
- // (i.e. off the previous page). This is different to the way the rest of
- // the code in this file is written, but it's easier for me to think about.
- // At some point we may refactor this to fit better with the rest of the
- // code.
-
- // screenWidth/Height are the actual width/height of the screen. e.g. 480/800
- int screenWidth = getWidth();
- int screenHeight = getHeight();
- // We might be mid scroll; we want to calculate where we scroll to based on
- // where this scroll would end, not where we are now (to allow for people
- // bashing 'forwards' very fast.
- int remainingX = mScroller.getFinalX() - mScroller.getCurrX();
- int remainingY = mScroller.getFinalY() - mScroller.getCurrY();
- // right/bottom is in terms of pixels within the scaled document; e.g. 1000
- int top = -(v.getTop() + mYScroll + remainingY);
- int right = screenWidth -(v.getLeft() + mXScroll + remainingX);
- int bottom = screenHeight+top;
- // docWidth/Height are the width/height of the scaled document e.g. 2000x3000
- int docWidth = v.getMeasuredWidth();
- int docHeight = v.getMeasuredHeight();
-
- int xOffset, yOffset;
- if (bottom >= docHeight) {
- // We are flush with the bottom. Advance to next column.
- if (right + screenWidth > docWidth) {
- // No room for another column - go to next page
- View nv = mChildViews.get(mCurrent+1);
- if (nv == null) // No page to advance to
- return;
- int nextTop = -(nv.getTop() + mYScroll + remainingY);
- int nextLeft = -(nv.getLeft() + mXScroll + remainingX);
- int nextDocWidth = nv.getMeasuredWidth();
- int nextDocHeight = nv.getMeasuredHeight();
-
- // Allow for the next page maybe being shorter than the screen is high
- yOffset = (nextDocHeight < screenHeight ? ((nextDocHeight - screenHeight)>>1) : 0);
-
- if (nextDocWidth < screenWidth) {
- // Next page is too narrow to fill the screen. Scroll to the top, centred.
- xOffset = (nextDocWidth - screenWidth)>>1;
- } else {
- // Reset X back to the left hand column
- xOffset = right % screenWidth;
- // Adjust in case the previous page is less wide
- if (xOffset + screenWidth > nextDocWidth)
- xOffset = nextDocWidth - screenWidth;
- }
- xOffset -= nextLeft;
- yOffset -= nextTop;
- } else {
- // Move to top of next column
- xOffset = screenWidth;
- yOffset = screenHeight - bottom;
- }
- } else {
- // Advance by 90% of the screen height downwards (in case lines are partially cut off)
- xOffset = 0;
- yOffset = smartAdvanceAmount(screenHeight, docHeight - bottom);
- }
- mScrollerLastX = mScrollerLastY = 0;
- mScroller.startScroll(0, 0, remainingX - xOffset, remainingY - yOffset, 400);
- mStepper.prod();
- }
-
- public void smartMoveBackwards() {
- View v = mChildViews.get(mCurrent);
- if (v == null)
- return;
-
- // The following code works in terms of where the screen is on the views;
- // so for example, if the currentView is at (-100,-100), the visible
- // region would be at (100,100). If the previous page was (2000, 3000) in
- // size, the visible region of the previous page might be (2100 + GAP, 100)
- // (i.e. off the previous page). This is different to the way the rest of
- // the code in this file is written, but it's easier for me to think about.
- // At some point we may refactor this to fit better with the rest of the
- // code.
-
- // screenWidth/Height are the actual width/height of the screen. e.g. 480/800
- int screenWidth = getWidth();
- int screenHeight = getHeight();
- // We might be mid scroll; we want to calculate where we scroll to based on
- // where this scroll would end, not where we are now (to allow for people
- // bashing 'forwards' very fast.
- int remainingX = mScroller.getFinalX() - mScroller.getCurrX();
- int remainingY = mScroller.getFinalY() - mScroller.getCurrY();
- // left/top is in terms of pixels within the scaled document; e.g. 1000
- int left = -(v.getLeft() + mXScroll + remainingX);
- int top = -(v.getTop() + mYScroll + remainingY);
- // docWidth/Height are the width/height of the scaled document e.g. 2000x3000
- int docHeight = v.getMeasuredHeight();
-
- int xOffset, yOffset;
- if (top <= 0) {
- // We are flush with the top. Step back to previous column.
- if (left < screenWidth) {
- /* No room for previous column - go to previous page */
- View pv = mChildViews.get(mCurrent-1);
- if (pv == null) /* No page to advance to */
- return;
- int prevDocWidth = pv.getMeasuredWidth();
- int prevDocHeight = pv.getMeasuredHeight();
-
- // Allow for the next page maybe being shorter than the screen is high
- yOffset = (prevDocHeight < screenHeight ? ((prevDocHeight - screenHeight)>>1) : 0);
-
- int prevLeft = -(pv.getLeft() + mXScroll);
- int prevTop = -(pv.getTop() + mYScroll);
- if (prevDocWidth < screenWidth) {
- // Previous page is too narrow to fill the screen. Scroll to the bottom, centred.
- xOffset = (prevDocWidth - screenWidth)>>1;
- } else {
- // Reset X back to the right hand column
- xOffset = (left > 0 ? left % screenWidth : 0);
- if (xOffset + screenWidth > prevDocWidth)
- xOffset = prevDocWidth - screenWidth;
- while (xOffset + screenWidth*2 < prevDocWidth)
- xOffset += screenWidth;
- }
- xOffset -= prevLeft;
- yOffset -= prevTop-prevDocHeight+screenHeight;
- } else {
- // Move to bottom of previous column
- xOffset = -screenWidth;
- yOffset = docHeight - screenHeight + top;
- }
- } else {
- // Retreat by 90% of the screen height downwards (in case lines are partially cut off)
- xOffset = 0;
- yOffset = -smartAdvanceAmount(screenHeight, top);
- }
- mScrollerLastX = mScrollerLastY = 0;
- mScroller.startScroll(0, 0, remainingX - xOffset, remainingY - yOffset, 400);
- mStepper.prod();
- }
-
- public void resetupChildren() {
- for (int i = 0; i < mChildViews.size(); i++)
- onChildSetup(mChildViews.keyAt(i), mChildViews.valueAt(i));
- }
-
- public void applyToChildren(ViewMapper mapper) {
- for (int i = 0; i < mChildViews.size(); i++)
- mapper.applyToView(mChildViews.valueAt(i));
- }
-
- public void refresh(boolean reflow) {
- mReflow = reflow;
- mReflowChanged = true;
- mResetLayout = true;
-
- mScale = 1.0f;
- mXScroll = mYScroll = 0;
-
- requestLayout();
- }
-
- protected void onChildSetup(int i, View v) {}
-
- protected void onMoveToChild(int i) {}
-
- protected void onMoveOffChild(int i) {}
-
- protected void onSettle(View v) {};
-
- protected void onUnsettle(View v) {};
-
- protected void onNotInUse(View v) {};
-
- protected void onScaleChild(View v, Float scale) {};
-
- public View getView(int i) {
- return mChildViews.get(i);
- }
-
- public View getDisplayedView() {
- return mChildViews.get(mCurrent);
- }
-
- public void run() {
- if (!mScroller.isFinished()) {
- mScroller.computeScrollOffset();
- int x = mScroller.getCurrX();
- int y = mScroller.getCurrY();
- mXScroll += x - mScrollerLastX;
- mYScroll += y - mScrollerLastY;
- mScrollerLastX = x;
- mScrollerLastY = y;
- requestLayout();
- mStepper.prod();
- }
- else if (!mUserInteracting) {
- // End of an inertial scroll and the user is not interacting.
- // The layout is stable
- View v = mChildViews.get(mCurrent);
- if (v != null)
- postSettle(v);
- }
- }
-
- public boolean onDown(MotionEvent arg0) {
- mScroller.forceFinished(true);
- return true;
- }
-
- public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
- float velocityY) {
- if (mScaling)
- return true;
-
- View v = mChildViews.get(mCurrent);
- if (v != null) {
- Rect bounds = getScrollBounds(v);
- switch(directionOfTravel(velocityX, velocityY)) {
- case MOVING_LEFT:
- if (HORIZONTAL_SCROLLING && bounds.left >= 0) {
- // Fling off to the left bring next view onto screen
- View vl = mChildViews.get(mCurrent+1);
-
- if (vl != null) {
- slideViewOntoScreen(vl);
- return true;
- }
- }
- break;
- case MOVING_UP:
- if (!HORIZONTAL_SCROLLING && bounds.top >= 0) {
- // Fling off to the top bring next view onto screen
- View vl = mChildViews.get(mCurrent+1);
-
- if (vl != null) {
- slideViewOntoScreen(vl);
- return true;
- }
- }
- break;
- case MOVING_RIGHT:
- if (HORIZONTAL_SCROLLING && bounds.right <= 0) {
- // Fling off to the right bring previous view onto screen
- View vr = mChildViews.get(mCurrent-1);
-
- if (vr != null) {
- slideViewOntoScreen(vr);
- return true;
- }
- }
- break;
- case MOVING_DOWN:
- if (!HORIZONTAL_SCROLLING && bounds.bottom <= 0) {
- // Fling off to the bottom bring previous view onto screen
- View vr = mChildViews.get(mCurrent-1);
-
- if (vr != null) {
- slideViewOntoScreen(vr);
- return true;
- }
- }
- break;
- }
- mScrollerLastX = mScrollerLastY = 0;
- // If the page has been dragged out of bounds then we want to spring back
- // nicely. fling jumps back into bounds instantly, so we don't want to use
- // fling in that case. On the other hand, we don't want to forgo a fling
- // just because of a slightly off-angle drag taking us out of bounds other
- // than in the direction of the drag, so we test for out of bounds only
- // in the direction of travel.
- //
- // Also don't fling if out of bounds in any direction by more than fling
- // margin
- Rect expandedBounds = new Rect(bounds);
- expandedBounds.inset(-FLING_MARGIN, -FLING_MARGIN);
-
- if(withinBoundsInDirectionOfTravel(bounds, velocityX, velocityY)
- && expandedBounds.contains(0, 0)) {
- mScroller.fling(0, 0, (int)velocityX, (int)velocityY, bounds.left, bounds.right, bounds.top, bounds.bottom);
- mStepper.prod();
- }
- }
-
- return true;
- }
-
- public void onLongPress(MotionEvent e) {
- }
-
- public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
- float distanceY) {
- if (!mScaling) {
- mXScroll -= distanceX;
- mYScroll -= distanceY;
- requestLayout();
- }
- return true;
- }
-
- public void onShowPress(MotionEvent e) {
- }
-
- public boolean onSingleTapUp(MotionEvent e) {
- return false;
- }
-
- public boolean onScale(ScaleGestureDetector detector) {
- float previousScale = mScale;
- float scale_factor = mReflow ? REFLOW_SCALE_FACTOR : 1.0f;
- float min_scale = MIN_SCALE * scale_factor;
- float max_scale = MAX_SCALE * scale_factor;
- mScale = Math.min(Math.max(mScale * detector.getScaleFactor(), min_scale), max_scale);
-
- if (mReflow) {
- View v = mChildViews.get(mCurrent);
- if (v != null)
- onScaleChild(v, mScale);
- } else {
- float factor = mScale/previousScale;
-
- View v = mChildViews.get(mCurrent);
- if (v != null) {
- float currentFocusX = detector.getFocusX();
- float currentFocusY = detector.getFocusY();
- // Work out the focus point relative to the view top left
- int viewFocusX = (int)currentFocusX - (v.getLeft() + mXScroll);
- int viewFocusY = (int)currentFocusY - (v.getTop() + mYScroll);
- // Scroll to maintain the focus point
- mXScroll += viewFocusX - viewFocusX * factor;
- mYScroll += viewFocusY - viewFocusY * factor;
-
- if (mLastScaleFocusX>=0)
- mXScroll+=currentFocusX-mLastScaleFocusX;
- if (mLastScaleFocusY>=0)
- mYScroll+=currentFocusY-mLastScaleFocusY;
-
- mLastScaleFocusX=currentFocusX;
- mLastScaleFocusY=currentFocusY;
- requestLayout();
- }
- }
- return true;
- }
-
- public boolean onScaleBegin(ScaleGestureDetector detector) {
- mScaling = true;
- // Ignore any scroll amounts yet to be accounted for: the
- // screen is not showing the effect of them, so they can
- // only confuse the user
- mXScroll = mYScroll = 0;
- mLastScaleFocusX = mLastScaleFocusY = -1;
- return true;
- }
-
- public void onScaleEnd(ScaleGestureDetector detector) {
- if (mReflow) {
- applyToChildren(new ViewMapper() {
- @Override
- void applyToView(View view) {
- onScaleChild(view, mScale);
- }
- });
- }
- mScaling = false;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- mScaleGestureDetector.onTouchEvent(event);
- mGestureDetector.onTouchEvent(event);
-
- if ((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN) {
- mUserInteracting = true;
- }
- if ((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_UP) {
- mUserInteracting = false;
-
- View v = mChildViews.get(mCurrent);
- if (v != null) {
- if (mScroller.isFinished()) {
- // If, at the end of user interaction, there is no
- // current inertial scroll in operation then animate
- // the view onto screen if necessary
- slideViewOntoScreen(v);
- }
-
- if (mScroller.isFinished()) {
- // If still there is no inertial scroll in operation
- // then the layout is stable
- postSettle(v);
- }
- }
- }
-
- requestLayout();
- return true;
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
- int n = getChildCount();
- for (int i = 0; i < n; i++)
- measureView(getChildAt(i));
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
-
- try {
- onLayout2(changed, left, top, right, bottom);
- }
- catch (java.lang.OutOfMemoryError e) {
- System.out.println("Out of memory during layout");
-
- // we might get an out of memory error.
- // so let's display an alert.
- // TODO: a better message, in resources.
-
- if (!memAlert) {
- memAlert = true;
- AlertDialog alertDialog = MuPDFActivity.getAlertBuilder().create();
- alertDialog.setMessage("Out of memory during layout");
- alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- memAlert = false;
- }
- });
- alertDialog.show();
- }
- }
- }
-
- private boolean memAlert = false;
-
- private void onLayout2(boolean changed, int left, int top, int right,
- int bottom) {
-
- // "Edit mode" means when the View is being displayed in the Android GUI editor. (this class
- // is instantiated in the IDE, so we need to be a bit careful what we do).
- if (isInEditMode())
- return;
-
- View cv = mChildViews.get(mCurrent);
- Point cvOffset;
-
- if (!mResetLayout) {
- // Move to next or previous if current is sufficiently off center
- if (cv != null) {
- boolean move;
- cvOffset = subScreenSizeOffset(cv);
- // cv.getRight() may be out of date with the current scale
- // so add left to the measured width for the correct position
- if (HORIZONTAL_SCROLLING)
- move = cv.getLeft() + cv.getMeasuredWidth() + cvOffset.x + GAP/2 + mXScroll < getWidth()/2;
- else
- move = cv.getTop() + cv.getMeasuredHeight() + cvOffset.y + GAP/2 + mYScroll < getHeight()/2;
- if (move && mCurrent + 1 < mAdapter.getCount()) {
- postUnsettle(cv);
- // post to invoke test for end of animation
- // where we must set hq area for the new current view
- mStepper.prod();
-
- onMoveOffChild(mCurrent);
- mCurrent++;
- onMoveToChild(mCurrent);
- }
-
- if (HORIZONTAL_SCROLLING)
- move = cv.getLeft() - cvOffset.x - GAP/2 + mXScroll >= getWidth()/2;
- else
- move = cv.getTop() - cvOffset.y - GAP/2 + mYScroll >= getHeight()/2;
- if (move && mCurrent > 0) {
- postUnsettle(cv);
- // post to invoke test for end of animation
- // where we must set hq area for the new current view
- mStepper.prod();
-
- onMoveOffChild(mCurrent);
- mCurrent--;
- onMoveToChild(mCurrent);
- }
- }
-
- // Remove not needed children and hold them for reuse
- int numChildren = mChildViews.size();
- int childIndices[] = new int[numChildren];
- for (int i = 0; i < numChildren; i++)
- childIndices[i] = mChildViews.keyAt(i);
-
- for (int i = 0; i < numChildren; i++) {
- int ai = childIndices[i];
- if (ai < mCurrent - 1 || ai > mCurrent + 1) {
- View v = mChildViews.get(ai);
- onNotInUse(v);
- mViewCache.add(v);
- removeViewInLayout(v);
- mChildViews.remove(ai);
- }
- }
- } else {
- mResetLayout = false;
- mXScroll = mYScroll = 0;
-
- // Remove all children and hold them for reuse
- int numChildren = mChildViews.size();
- for (int i = 0; i < numChildren; i++) {
- View v = mChildViews.valueAt(i);
- onNotInUse(v);
- mViewCache.add(v);
- removeViewInLayout(v);
- }
- mChildViews.clear();
-
- // Don't reuse cached views if the adapter has changed
- if (mReflowChanged) {
- mReflowChanged = false;
- mViewCache.clear();
- }
-
- // post to ensure generation of hq area
- mStepper.prod();
- }
-
- // Ensure current view is present
- int cvLeft, cvRight, cvTop, cvBottom;
- boolean notPresent = (mChildViews.get(mCurrent) == null);
- cv = getOrCreateChild(mCurrent);
- // When the view is sub-screen-size in either dimension we
- // offset it to center within the screen area, and to keep
- // the views spaced out
- cvOffset = subScreenSizeOffset(cv);
- if (notPresent) {
- //Main item not already present. Just place it top left
- cvLeft = cvOffset.x;
- cvTop = cvOffset.y;
- } else {
- // Main item already present. Adjust by scroll offsets
- cvLeft = cv.getLeft() + mXScroll;
- cvTop = cv.getTop() + mYScroll;
- }
- // Scroll values have been accounted for
- mXScroll = mYScroll = 0;
- cvRight = cvLeft + cv.getMeasuredWidth();
- cvBottom = cvTop + cv.getMeasuredHeight();
-
- if (!mUserInteracting && mScroller.isFinished()) {
- Point corr = getCorrection(getScrollBounds(cvLeft, cvTop, cvRight, cvBottom));
- cvRight += corr.x;
- cvLeft += corr.x;
- cvTop += corr.y;
- cvBottom += corr.y;
- } else if (HORIZONTAL_SCROLLING && cv.getMeasuredHeight() <= getHeight()) {
- // When the current view is as small as the screen in height, clamp
- // it vertically
- Point corr = getCorrection(getScrollBounds(cvLeft, cvTop, cvRight, cvBottom));
- cvTop += corr.y;
- cvBottom += corr.y;
- } else if (!HORIZONTAL_SCROLLING && cv.getMeasuredWidth() <= getWidth()) {
- // When the current view is as small as the screen in width, clamp
- // it horizontally
- Point corr = getCorrection(getScrollBounds(cvLeft, cvTop, cvRight, cvBottom));
- cvRight += corr.x;
- cvLeft += corr.x;
- }
-
- cv.layout(cvLeft, cvTop, cvRight, cvBottom);
-
- if (mCurrent > 0) {
- View lv = getOrCreateChild(mCurrent - 1);
- Point leftOffset = subScreenSizeOffset(lv);
- if (HORIZONTAL_SCROLLING)
- {
- int gap = leftOffset.x + GAP + cvOffset.x;
- lv.layout(cvLeft - lv.getMeasuredWidth() - gap,
- (cvBottom + cvTop - lv.getMeasuredHeight())/2,
- cvLeft - gap,
- (cvBottom + cvTop + lv.getMeasuredHeight())/2);
- } else {
- int gap = leftOffset.y + GAP + cvOffset.y;
- lv.layout((cvLeft + cvRight - lv.getMeasuredWidth())/2,
- cvTop - lv.getMeasuredHeight() - gap,
- (cvLeft + cvRight + lv.getMeasuredWidth())/2,
- cvTop - gap);
- }
- }
-
- if (mCurrent + 1 < mAdapter.getCount()) {
- View rv = getOrCreateChild(mCurrent + 1);
- Point rightOffset = subScreenSizeOffset(rv);
- if (HORIZONTAL_SCROLLING)
- {
- int gap = cvOffset.x + GAP + rightOffset.x;
- rv.layout(cvRight + gap,
- (cvBottom + cvTop - rv.getMeasuredHeight())/2,
- cvRight + rv.getMeasuredWidth() + gap,
- (cvBottom + cvTop + rv.getMeasuredHeight())/2);
- } else {
- int gap = cvOffset.y + GAP + rightOffset.y;
- rv.layout((cvLeft + cvRight - rv.getMeasuredWidth())/2,
- cvBottom + gap,
- (cvLeft + cvRight + rv.getMeasuredWidth())/2,
- cvBottom + gap + rv.getMeasuredHeight());
- }
- }
-
- invalidate();
- }
-
- @Override
- public Adapter getAdapter() {
- return mAdapter;
- }
-
- @Override
- public View getSelectedView() {
- return null;
- }
-
- @Override
- public void setAdapter(Adapter adapter) {
-
- // release previous adapter's bitmaps
- if (null!=mAdapter && adapter!=mAdapter) {
- if (adapter instanceof MuPDFPageAdapter){
- ((MuPDFPageAdapter) adapter).releaseBitmaps();
- }
- }
-
- mAdapter = adapter;
-
- requestLayout();
- }
-
- @Override
- public void setSelection(int arg0) {
- throw new UnsupportedOperationException(getContext().getString(R.string.not_supported));
- }
-
- private View getCached() {
- if (mViewCache.size() == 0)
- return null;
- else
- return mViewCache.removeFirst();
- }
-
- private View getOrCreateChild(int i) {
- View v = mChildViews.get(i);
- if (v == null) {
- v = mAdapter.getView(i, getCached(), this);
- addAndMeasureChild(i, v);
- onChildSetup(i, v);
- onScaleChild(v, mScale);
- }
-
- return v;
- }
-
- private void addAndMeasureChild(int i, View v) {
- LayoutParams params = v.getLayoutParams();
- if (params == null) {
- params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
- }
- addViewInLayout(v, 0, params, true);
- mChildViews.append(i, v); // Record the view against it's adapter index
- measureView(v);
- }
-
- private void measureView(View v) {
- // See what size the view wants to be
- v.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
-
- if (!mReflow) {
- // Work out a scale that will fit it to this view
- float scale = Math.min((float)getWidth()/(float)v.getMeasuredWidth(),
- (float)getHeight()/(float)v.getMeasuredHeight());
- // Use the fitting values scaled by our current scale factor
- v.measure(View.MeasureSpec.EXACTLY | (int)(v.getMeasuredWidth()*scale*mScale),
- View.MeasureSpec.EXACTLY | (int)(v.getMeasuredHeight()*scale*mScale));
- } else {
- v.measure(View.MeasureSpec.EXACTLY | (int)(v.getMeasuredWidth()),
- View.MeasureSpec.EXACTLY | (int)(v.getMeasuredHeight()));
- }
- }
-
- private Rect getScrollBounds(int left, int top, int right, int bottom) {
- int xmin = getWidth() - right;
- int xmax = -left;
- int ymin = getHeight() - bottom;
- int ymax = -top;
-
- // In either dimension, if view smaller than screen then
- // constrain it to be central
- if (xmin > xmax) xmin = xmax = (xmin + xmax)/2;
- if (ymin > ymax) ymin = ymax = (ymin + ymax)/2;
-
- return new Rect(xmin, ymin, xmax, ymax);
- }
-
- private Rect getScrollBounds(View v) {
- // There can be scroll amounts not yet accounted for in
- // onLayout, so add mXScroll and mYScroll to the current
- // positions when calculating the bounds.
- return getScrollBounds(v.getLeft() + mXScroll,
- v.getTop() + mYScroll,
- v.getLeft() + v.getMeasuredWidth() + mXScroll,
- v.getTop() + v.getMeasuredHeight() + mYScroll);
- }
-
- private Point getCorrection(Rect bounds) {
- return new Point(Math.min(Math.max(0,bounds.left),bounds.right),
- Math.min(Math.max(0,bounds.top),bounds.bottom));
- }
-
- private void postSettle(final View v) {
- // onSettle and onUnsettle are posted so that the calls
- // wont be executed until after the system has performed
- // layout.
- post (new Runnable() {
- public void run () {
- onSettle(v);
- }
- });
- }
-
- private void postUnsettle(final View v) {
- post (new Runnable() {
- public void run () {
- onUnsettle(v);
- }
- });
- }
-
- private void slideViewOntoScreen(View v) {
- Point corr = getCorrection(getScrollBounds(v));
- if (corr.x != 0 || corr.y != 0) {
- mScrollerLastX = mScrollerLastY = 0;
- mScroller.startScroll(0, 0, corr.x, corr.y, 400);
- mStepper.prod();
- }
- }
-
- private Point subScreenSizeOffset(View v) {
- return new Point(Math.max((getWidth() - v.getMeasuredWidth())/2, 0),
- Math.max((getHeight() - v.getMeasuredHeight())/2, 0));
- }
-
- private static int directionOfTravel(float vx, float vy) {
- if (Math.abs(vx) > 2 * Math.abs(vy))
- return (vx > 0) ? MOVING_RIGHT : MOVING_LEFT;
- else if (Math.abs(vy) > 2 * Math.abs(vx))
- return (vy > 0) ? MOVING_DOWN : MOVING_UP;
- else
- return MOVING_DIAGONALLY;
- }
-
- private static boolean withinBoundsInDirectionOfTravel(Rect bounds, float vx, float vy) {
- switch (directionOfTravel(vx, vy)) {
- case MOVING_DIAGONALLY: return bounds.contains(0, 0);
- case MOVING_LEFT: return bounds.left <= 0;
- case MOVING_RIGHT: return bounds.right >= 0;
- case MOVING_UP: return bounds.top <= 0;
- case MOVING_DOWN: return bounds.bottom >= 0;
- default: throw new NoSuchElementException();
- }
- }
-}