diff --git a/CHANGELOG.md b/CHANGELOG.md index dbee53f8..7652d133 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +## 3.2.0-beta.1 (2019-08-18) +* Merge PR #714 with optimized page load +* Merge PR #776 with fix for max & min zoom level +* Merge PR #722 with fix for showing right position when view size changed +* Merge PR #703 with fix for too many threads +* Merge PR #702 with fix for memory leak +* Merge PR #689 with possibility to disable long click +* Merge PR #628 with fix for hiding scroll handle +* Merge PR #627 with `fitEachPage` option +* Merge PR #638 and #406 with fixed NPE +* Merge PR #780 with README fix +* Update compile SDK and support library to 28 +* Update Gradle and Gradle Plugin + ## 3.1.0-beta.1 (2018-06-29) * Merge pull request #557 for snapping pages (scrolling page by page) * merge pull request #618 for night mode diff --git a/README.md b/README.md index 3575eaea..812c6e9d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ +# Change of ownership and looking for contributors! + +The ownership of the project was recently changed and we are actively looking for contributors to bring the project back to track. Please [visit](https://github.com/DImuthuUpe/AndroidPdfViewer/issues/1186) # Android PdfViewer @@ -10,14 +13,19 @@ Library for displaying PDF documents on Android, with `animations`, `gestures`, It is based on [PdfiumAndroid](https://github.com/barteksc/PdfiumAndroid) for decoding PDF files. Works on API 11 (Android 3.0) and higher. Licensed under Apache License 2.0. -## What's new in 3.1.0-beta.1? -* Merge pull request #557 for snapping pages (scrolling page by page) -* merge pull request #618 for night mode -* Merge pull request #566 for `OnLongTapListener` -* Update PdfiumAndroid to 1.9.0, which uses `c++_shared` instead of `gnustl_static` -* Update Gradle Plugin -* Update compile SDK and support library to 26 -* Change minimum SDK to 14 +## What's new in 3.2.0-beta.1? +* Merge PR #714 with optimized page load +* Merge PR #776 with fix for max & min zoom level +* Merge PR #722 with fix for showing right position when view size changed +* Merge PR #703 with fix for too many threads +* Merge PR #702 with fix for memory leak +* Merge PR #689 with possibility to disable long click +* Merge PR #628 with fix for hiding scroll handle +* Merge PR #627 with `fitEachPage` option +* Merge PR #638 and #406 with fixed NPE +* Merge PR #780 with README fix +* Update compile SDK and support library to 28 +* Update Gradle and Gradle Plugin ## Changes in 3.0 API * Replaced `Contants.PRELOAD_COUNT` with `PRELOAD_OFFSET` @@ -30,11 +38,11 @@ Licensed under Apache License 2.0. Add to _build.gradle_: -`compile 'com.github.barteksc:android-pdf-viewer:3.1.0-beta.1'` +`implementation 'com.github.barteksc:android-pdf-viewer:3.2.0-beta.1'` or if you want to use more stable version: -`compile 'com.github.barteksc:android-pdf-viewer:2.8.2'` +`implementation 'com.github.barteksc:android-pdf-viewer:2.8.2'` Library is available in jcenter repository, probably it'll be in Maven Central soon. @@ -95,8 +103,9 @@ pdfView.fromAsset(String) .spacing(0) .autoSpacing(false) // add dynamic spacing to fit each page on its own on the screen .linkHandler(DefaultLinkHandler) - .pageFitPolicy(FitPolicy.WIDTH) - .pageSnap(true) // snap pages to screen boundaries + .pageFitPolicy(FitPolicy.WIDTH) // mode to fit pages in the view + .fitEachPage(false) // fit each page to the view, else smaller pages are scaled relative to largest page. + .pageSnap(false) // snap pages to screen boundaries .pageFling(false) // make a fling change only a single page like ViewPager .nightMode(false) // toggle night mode .load(); diff --git a/android-pdf-viewer/bintray.gradle b/android-pdf-viewer/bintray.gradle new file mode 100644 index 00000000..9a01f197 --- /dev/null +++ b/android-pdf-viewer/bintray.gradle @@ -0,0 +1,89 @@ +apply plugin: 'com.github.dcendents.android-maven' +apply plugin: 'com.jfrog.bintray' + +group = publishedGroupId +version = libraryVersion + +install { + repositories.mavenInstaller { + pom.project { + packaging 'aar' + groupId publishedGroupId + artifactId artifact + + name libraryName + description libraryDescription + url siteUrl + + licenses { + license { + name licenseName + url licenseUrl + } + } + developers { + developer { + id developerId + name developerName + email developerEmail + } + } + scm { + connection gitUrl + developerConnection gitUrl + url siteUrl + } + } + } +} + +task sourcesJar(type: Jar) { + classifier = 'sources' + from android.sourceSets.main.java.srcDirs +} + +task javadoc(type: Javadoc) { + source = android.sourceSets.main.java.srcDirs + classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) +} + +afterEvaluate { + javadoc.classpath += files(android.libraryVariants.collect { variant -> + variant.javaCompileProvider.get().classpath.files + }) +} + +task javadocJar(type: Jar, dependsOn: javadoc) { + classifier = 'javadoc' + from javadoc.destinationDir +} + +artifacts { + archives javadocJar + archives sourcesJar +} + +Properties properties = new Properties() +properties.load(project.rootProject.file('local.properties').newDataInputStream()) + +bintray { + user = properties.getProperty("bintray.user") + key = properties.getProperty("bintray.apikey") + + configurations = ['archives'] + pkg { + repo = bintrayRepo + name = bintrayName + desc = libraryDescription + websiteUrl = siteUrl + vcsUrl = gitUrl + licenses = allLicenses + dryRun = false + publish = true + override = false + publicDownloadNumbers = true + version { + desc = libraryDescription + } + } +} \ No newline at end of file diff --git a/android-pdf-viewer/build.gradle b/android-pdf-viewer/build.gradle index 784ac639..32d03665 100644 --- a/android-pdf-viewer/build.gradle +++ b/android-pdf-viewer/build.gradle @@ -13,7 +13,7 @@ ext { siteUrl = 'https://github.com/barteksc/AndroidPdfViewer' gitUrl = 'https://github.com/barteksc/AndroidPdfViewer.git' - libraryVersion = '3.1.0-beta.1' + libraryVersion = '3.2.0-beta.1' developerId = 'barteksc' developerName = 'Bartosz Schiller' @@ -25,21 +25,20 @@ ext { } android { - compileSdkVersion 26 + compileSdkVersion 28 defaultConfig { minSdkVersion 14 - targetSdkVersion 26 + targetSdkVersion 28 versionCode 1 - versionName "3.1.0-beta.1" + versionName "3.2.0-beta.1" } } dependencies { - implementation 'com.android.support:support-compat:26.1.0' + implementation 'com.android.support:support-compat:28.0.0' api 'com.github.barteksc:pdfium-android:1.9.0' } -apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/installv1.gradle' -apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/bintrayv1.gradle' \ No newline at end of file +apply from: 'bintray.gradle' \ No newline at end of file diff --git a/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/AnimationManager.java b/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/AnimationManager.java index 67ab7f3b..e7e9439f 100644 --- a/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/AnimationManager.java +++ b/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/AnimationManager.java @@ -138,12 +138,14 @@ public void onAnimationUpdate(ValueAnimator animation) { public void onAnimationCancel(Animator animation) { pdfView.loadPages(); pageFlinging = false; + hideHandle(); } @Override public void onAnimationEnd(Animator animation) { pdfView.loadPages(); pageFlinging = false; + hideHandle(); } } @@ -160,12 +162,14 @@ public void onAnimationUpdate(ValueAnimator animation) { public void onAnimationCancel(Animator animation) { pdfView.loadPages(); pageFlinging = false; + hideHandle(); } @Override public void onAnimationEnd(Animator animation) { pdfView.loadPages(); pageFlinging = false; + hideHandle(); } } @@ -187,13 +191,15 @@ public void onAnimationUpdate(ValueAnimator animation) { @Override public void onAnimationCancel(Animator animation) { + pdfView.loadPages(); + hideHandle(); } @Override public void onAnimationEnd(Animator animation) { pdfView.loadPages(); - hideHandle(); pdfView.performPageSnap(); + hideHandle(); } @Override diff --git a/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/DecodingAsyncTask.java b/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/DecodingAsyncTask.java index a28974ba..24292ac9 100644 --- a/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/DecodingAsyncTask.java +++ b/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/DecodingAsyncTask.java @@ -1,77 +1,89 @@ -/** - * Copyright 2016 Bartosz Schiller - *

- * 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 com.github.barteksc.pdfviewer; - -import android.os.AsyncTask; - -import com.github.barteksc.pdfviewer.source.DocumentSource; -import com.shockwave.pdfium.PdfDocument; -import com.shockwave.pdfium.PdfiumCore; -import com.shockwave.pdfium.util.Size; - -class DecodingAsyncTask extends AsyncTask { - - private boolean cancelled; - - private PDFView pdfView; - - private PdfiumCore pdfiumCore; - private String password; - private DocumentSource docSource; - private int[] userPages; - private PdfFile pdfFile; - - DecodingAsyncTask(DocumentSource docSource, String password, int[] userPages, PDFView pdfView, PdfiumCore pdfiumCore) { - this.docSource = docSource; - this.userPages = userPages; - this.cancelled = false; - this.pdfView = pdfView; - this.password = password; - this.pdfiumCore = pdfiumCore; - } - - @Override - protected Throwable doInBackground(Void... params) { - try { - PdfDocument pdfDocument = docSource.createDocument(pdfView.getContext(), pdfiumCore, password); - pdfFile = new PdfFile(pdfiumCore, pdfDocument, pdfView.getPageFitPolicy(), getViewSize(), - userPages, pdfView.isSwipeVertical(), pdfView.getSpacingPx(), pdfView.doAutoSpacing()); - return null; - } catch (Throwable t) { - return t; - } - } - - private Size getViewSize() { - return new Size(pdfView.getWidth(), pdfView.getHeight()); - } - - @Override - protected void onPostExecute(Throwable t) { - if (t != null) { - pdfView.loadError(t); - return; - } - if (!cancelled) { - pdfView.loadComplete(pdfFile); - } - } - - @Override - protected void onCancelled() { - cancelled = true; - } -} +/** + * Copyright 2016 Bartosz Schiller + *

+ * 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 com.github.barteksc.pdfviewer; + +import android.os.AsyncTask; + +import com.github.barteksc.pdfviewer.source.DocumentSource; +import com.shockwave.pdfium.PdfDocument; +import com.shockwave.pdfium.PdfiumCore; +import com.shockwave.pdfium.util.Size; + +import java.lang.ref.WeakReference; + +class DecodingAsyncTask extends AsyncTask { + + private boolean cancelled; + + private WeakReference pdfViewReference; + + private PdfiumCore pdfiumCore; + private String password; + private DocumentSource docSource; + private int[] userPages; + private PdfFile pdfFile; + + DecodingAsyncTask(DocumentSource docSource, String password, int[] userPages, PDFView pdfView, PdfiumCore pdfiumCore) { + this.docSource = docSource; + this.userPages = userPages; + this.cancelled = false; + this.pdfViewReference = new WeakReference<>(pdfView); + this.password = password; + this.pdfiumCore = pdfiumCore; + } + + @Override + protected Throwable doInBackground(Void... params) { + try { + PDFView pdfView = pdfViewReference.get(); + if (pdfView != null) { + PdfDocument pdfDocument = docSource.createDocument(pdfView.getContext(), pdfiumCore, password); + pdfFile = new PdfFile(pdfiumCore, pdfDocument, pdfView.getPageFitPolicy(), getViewSize(pdfView), + userPages, pdfView.isSwipeVertical(), pdfView.getSpacingPx(), pdfView.isAutoSpacingEnabled(), + pdfView.isFitEachPage()); + return null; + } else { + return new NullPointerException("pdfView == null"); + } + + } catch (Throwable t) { + return t; + } + } + + private Size getViewSize(PDFView pdfView) { + return new Size(pdfView.getWidth(), pdfView.getHeight()); + } + + @Override + protected void onPostExecute(Throwable t) { + PDFView pdfView = pdfViewReference.get(); + if (pdfView != null) { + if (t != null) { + pdfView.loadError(t); + return; + } + if (!cancelled) { + pdfView.loadComplete(pdfFile); + } + } + } + + @Override + protected void onCancelled() { + cancelled = true; + } +} diff --git a/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/DragPinchManager.java b/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/DragPinchManager.java index fa7fc33a..3860bc73 100644 --- a/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/DragPinchManager.java +++ b/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/DragPinchManager.java @@ -63,6 +63,10 @@ void disable() { enabled = false; } + void disableLongpress(){ + gestureDetector.setIsLongpressEnabled(false); + } + @Override public boolean onSingleTapConfirmed(MotionEvent e) { boolean onTapHandled = pdfView.callbacks.callOnTap(e); @@ -83,6 +87,9 @@ public boolean onSingleTapConfirmed(MotionEvent e) { private boolean checkLinkTapped(float x, float y) { PdfFile pdfFile = pdfView.pdfFile; + if (pdfFile == null) { + return false; + } float mappedX = -pdfView.getCurrentXOffset() + x; float mappedY = -pdfView.getCurrentYOffset() + y; int page = pdfFile.getPageAtOffset(pdfView.isSwipeVertical() ? mappedY : mappedX, pdfView.getZoom()); @@ -197,7 +204,7 @@ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float ve if (!pdfView.isSwipeEnabled()) { return false; } - if (pdfView.doPageFling()) { + if (pdfView.isPageFlingEnabled()) { if (pdfView.pageFillsScreen()) { onBoundedFling(velocityX, velocityY); } else { @@ -253,10 +260,12 @@ private void onBoundedFling(float velocityX, float velocityY) { public boolean onScale(ScaleGestureDetector detector) { float dr = detector.getScaleFactor(); float wantedZoom = pdfView.getZoom() * dr; - if (wantedZoom < MINIMUM_ZOOM) { - dr = MINIMUM_ZOOM / pdfView.getZoom(); - } else if (wantedZoom > MAXIMUM_ZOOM) { - dr = MAXIMUM_ZOOM / pdfView.getZoom(); + float minZoom = Math.min(MINIMUM_ZOOM, pdfView.getMinZoom()); + float maxZoom = Math.min(MAXIMUM_ZOOM, pdfView.getMaxZoom()); + if (wantedZoom < minZoom) { + dr = minZoom / pdfView.getZoom(); + } else if (wantedZoom > maxZoom) { + dr = maxZoom / pdfView.getZoom(); } pdfView.zoomCenteredRelativeTo(dr, new PointF(detector.getFocusX(), detector.getFocusY())); return true; diff --git a/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/PDFView.java b/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/PDFView.java index 5e9636e7..b8374721 100644 --- a/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/PDFView.java +++ b/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/PDFView.java @@ -30,6 +30,7 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.AsyncTask; +import android.os.Build; import android.os.HandlerThread; import android.util.AttributeSet; import android.util.Log; @@ -154,7 +155,7 @@ enum ScrollDir { private DecodingAsyncTask decodingAsyncTask; /** The thread {@link #renderingHandler} will run on */ - private final HandlerThread renderingHandlerThread; + private HandlerThread renderingHandlerThread; /** Handler always waiting in the background and rendering tasks */ RenderingHandler renderingHandler; @@ -171,6 +172,8 @@ enum ScrollDir { /** Policy for fitting pages to screen */ private FitPolicy pageFitPolicy = FitPolicy.WIDTH; + private boolean fitEachPage = false; + private int defaultPage = 0; /** True if should scroll through pages vertically instead of horizontally */ @@ -462,6 +465,14 @@ public void computeScroll() { @Override protected void onDetachedFromWindow() { recycle(); + if (renderingHandlerThread != null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { + renderingHandlerThread.quitSafely(); + } else { + renderingHandlerThread.quit(); + } + renderingHandlerThread = null; + } super.onDetachedFromWindow(); } @@ -474,13 +485,33 @@ protected void onSizeChanged(int w, int h, int oldw, int oldh) { if (isInEditMode() || state != State.SHOWN) { return; } + + // calculates the position of the point which in the center of view relative to big strip + float centerPointInStripXOffset = -currentXOffset + oldw * 0.5f; + float centerPointInStripYOffset = -currentYOffset + oldh * 0.5f; + + float relativeCenterPointInStripXOffset; + float relativeCenterPointInStripYOffset; + + if (swipeVertical){ + relativeCenterPointInStripXOffset = centerPointInStripXOffset / pdfFile.getMaxPageWidth(); + relativeCenterPointInStripYOffset = centerPointInStripYOffset / pdfFile.getDocLen(zoom); + }else { + relativeCenterPointInStripXOffset = centerPointInStripXOffset / pdfFile.getDocLen(zoom); + relativeCenterPointInStripYOffset = centerPointInStripYOffset / pdfFile.getMaxPageHeight(); + } + animationManager.stopAll(); pdfFile.recalculatePageSizes(new Size(w, h)); + if (swipeVertical) { - moveTo(currentXOffset, -pdfFile.getPageOffset(currentPage, zoom)); - } else { - moveTo(-pdfFile.getPageOffset(currentPage, zoom), currentYOffset); + currentXOffset = -relativeCenterPointInStripXOffset * pdfFile.getMaxPageWidth() + w * 0.5f; + currentYOffset = -relativeCenterPointInStripYOffset * pdfFile.getDocLen(zoom) + h * 0.5f ; + }else { + currentXOffset = -relativeCenterPointInStripXOffset * pdfFile.getDocLen(zoom) + w * 0.5f; + currentYOffset = -relativeCenterPointInStripYOffset * pdfFile.getMaxPageHeight() + h * 0.5f; } + moveTo(currentXOffset,currentYOffset); loadPageByOffset(); } @@ -1184,7 +1215,7 @@ public int getSpacingPx() { return spacingPx; } - public boolean doAutoSpacing() { + public boolean isAutoSpacingEnabled() { return autoSpacing; } @@ -1192,12 +1223,12 @@ public void setPageFling(boolean pageFling) { this.pageFling = pageFling; } - public boolean doPageFling() { + public boolean isPageFlingEnabled() { return pageFling; } - private void setSpacing(int spacing) { - this.spacingPx = Util.getDP(getContext(), spacing); + private void setSpacing(int spacingDp) { + this.spacingPx = Util.getDP(getContext(), spacingDp); } private void setAutoSpacing(boolean autoSpacing) { @@ -1212,7 +1243,15 @@ public FitPolicy getPageFitPolicy() { return pageFitPolicy; } - public boolean doPageSnap() { + private void setFitEachPage(boolean fitEachPage) { + this.fitEachPage = fitEachPage; + } + + public boolean isFitEachPage() { + return fitEachPage; + } + + public boolean isPageSnap() { return pageSnap; } @@ -1330,6 +1369,8 @@ public class Configurator { private FitPolicy pageFitPolicy = FitPolicy.WIDTH; + private boolean fitEachPage = false; + private boolean pageFling = false; private boolean pageSnap = false; @@ -1455,6 +1496,11 @@ public Configurator pageFitPolicy(FitPolicy pageFitPolicy) { return this; } + public Configurator fitEachPage(boolean fitEachPage) { + this.fitEachPage = fitEachPage; + return this; + } + public Configurator pageSnap(boolean pageSnap) { this.pageSnap = pageSnap; return this; @@ -1470,6 +1516,11 @@ public Configurator nightMode(boolean nightMode) { return this; } + public Configurator disableLongpress() { + PDFView.this.dragPinchManager.disableLongpress(); + return this; + } + public void load() { if (!hasSize) { waitingDocumentConfigurator = this; @@ -1498,6 +1549,7 @@ public void load() { PDFView.this.setSpacing(spacing); PDFView.this.setAutoSpacing(autoSpacing); PDFView.this.setPageFitPolicy(pageFitPolicy); + PDFView.this.setFitEachPage(fitEachPage); PDFView.this.setPageSnap(pageSnap); PDFView.this.setPageFling(pageFling); diff --git a/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/PagesLoader.java b/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/PagesLoader.java index bd7cf098..26c30f4b 100644 --- a/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/PagesLoader.java +++ b/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/PagesLoader.java @@ -22,6 +22,9 @@ import com.github.barteksc.pdfviewer.util.Util; import com.shockwave.pdfium.util.SizeF; +import java.util.LinkedList; +import java.util.List; + import static com.github.barteksc.pdfviewer.util.Constants.Cache.CACHE_SIZE; import static com.github.barteksc.pdfviewer.util.Constants.PRELOAD_OFFSET; @@ -37,21 +40,55 @@ class PagesLoader { private float partRenderHeight; private final RectF thumbnailRect = new RectF(0, 0, 1, 1); private final int preloadOffset; - private final Holder firstHolder = new Holder(); - private final Holder lastHolder = new Holder(); - private final GridSize firstGrid = new GridSize(); - private final GridSize lastGrid = new GridSize(); - private final GridSize middleGrid = new GridSize(); private class Holder { - int page; int row; int col; + + @Override + public String toString() { + return "Holder{" + + "row=" + row + + ", col=" + col + + '}'; + } + } + + private class RenderRange { + int page; + GridSize gridSize; + Holder leftTop; + Holder rightBottom; + + RenderRange() { + this.page = 0; + this.gridSize = new GridSize(); + this.leftTop = new Holder(); + this.rightBottom = new Holder(); + } + + @Override + public String toString() { + return "RenderRange{" + + "page=" + page + + ", gridSize=" + gridSize + + ", leftTop=" + leftTop + + ", rightBottom=" + rightBottom + + '}'; + } } private class GridSize { int rows; int cols; + + @Override + public String toString() { + return "GridSize{" + + "rows=" + rows + + ", cols=" + cols + + '}'; + } } PagesLoader(PDFView pdfView) { @@ -69,36 +106,6 @@ private void getPageColsRows(GridSize grid, int pageIndex) { grid.cols = MathUtils.ceil(1f / partWidth); } - private Holder getPageAndCoordsByOffset(Holder holder, GridSize grid, float localXOffset, - float localYOffset, boolean endOffset) { - float fixedXOffset = -MathUtils.max(localXOffset, 0); - float fixedYOffset = -MathUtils.max(localYOffset, 0); - float offset = pdfView.isSwipeVertical() ? fixedYOffset : fixedXOffset; - holder.page = pdfView.pdfFile.getPageAtOffset(offset, pdfView.getZoom()); - getPageColsRows(grid, holder.page); - SizeF scaledPageSize = pdfView.pdfFile.getScaledPageSize(holder.page, pdfView.getZoom()); - float rowHeight = scaledPageSize.getHeight() / grid.rows; - float colWidth = scaledPageSize.getWidth() / grid.cols; - float row, col; - float secondaryOffset = pdfView.pdfFile.getSecondaryPageOffset(holder.page, pdfView.getZoom()); - if (pdfView.isSwipeVertical()) { - row = Math.abs(fixedYOffset - pdfView.pdfFile.getPageOffset(holder.page, pdfView.getZoom())) / rowHeight; - col = MathUtils.min(fixedXOffset - secondaryOffset, 0) / colWidth; - } else { - col = Math.abs(fixedXOffset - pdfView.pdfFile.getPageOffset(holder.page, pdfView.getZoom())) / colWidth; - row = MathUtils.min(fixedYOffset - secondaryOffset, 0) / rowHeight; - } - - if (endOffset) { - holder.row = MathUtils.ceil(row); - holder.col = MathUtils.ceil(col); - } else { - holder.row = MathUtils.floor(row); - holder.col = MathUtils.floor(col); - } - return holder; - } - private void calculatePartSize(GridSize grid) { pageRelativePartWidth = 1f / (float) grid.cols; pageRelativePartHeight = 1f / (float) grid.rows; @@ -106,87 +113,137 @@ private void calculatePartSize(GridSize grid) { partRenderHeight = Constants.PART_SIZE / pageRelativePartHeight; } - private void loadVisible() { - int parts = 0; - float scaledPreloadOffset = preloadOffset * pdfView.getZoom(); - float firstXOffset = -xOffset + scaledPreloadOffset; - float lastXOffset = -xOffset - pdfView.getWidth() - scaledPreloadOffset; - float firstYOffset = -yOffset + scaledPreloadOffset; - float lastYOffset = -yOffset - pdfView.getHeight() - scaledPreloadOffset; - getPageAndCoordsByOffset(firstHolder, firstGrid, firstXOffset, firstYOffset, false); - getPageAndCoordsByOffset(lastHolder, lastGrid, lastXOffset, lastYOffset, true); + /** + * calculate the render range of each page + */ + private List getRenderRangeList(float firstXOffset, float firstYOffset, float lastXOffset, float lastYOffset) { + + float fixedFirstXOffset = -MathUtils.max(firstXOffset, 0); + float fixedFirstYOffset = -MathUtils.max(firstYOffset, 0); + + float fixedLastXOffset = -MathUtils.max(lastXOffset, 0); + float fixedLastYOffset = -MathUtils.max(lastYOffset, 0); + + float offsetFirst = pdfView.isSwipeVertical() ? fixedFirstYOffset : fixedFirstXOffset; + float offsetLast = pdfView.isSwipeVertical() ? fixedLastYOffset : fixedLastXOffset; + + int firstPage = pdfView.pdfFile.getPageAtOffset(offsetFirst, pdfView.getZoom()); + int lastPage = pdfView.pdfFile.getPageAtOffset(offsetLast, pdfView.getZoom()); + int pageCount = lastPage - firstPage + 1; + + List renderRanges = new LinkedList<>(); + + for (int page = firstPage; page <= lastPage; page++) { + RenderRange range = new RenderRange(); + range.page = page; + + float pageFirstXOffset, pageFirstYOffset, pageLastXOffset, pageLastYOffset; + if (page == firstPage) { + pageFirstXOffset = fixedFirstXOffset; + pageFirstYOffset = fixedFirstYOffset; + if (pageCount == 1) { + pageLastXOffset = fixedLastXOffset; + pageLastYOffset = fixedLastYOffset; + } else { + float pageOffset = pdfView.pdfFile.getPageOffset(page, pdfView.getZoom()); + SizeF pageSize = pdfView.pdfFile.getScaledPageSize(page, pdfView.getZoom()); + if (pdfView.isSwipeVertical()) { + pageLastXOffset = fixedLastXOffset; + pageLastYOffset = pageOffset + pageSize.getHeight(); + } else { + pageLastYOffset = fixedLastYOffset; + pageLastXOffset = pageOffset + pageSize.getWidth(); + } + } + } else if (page == lastPage) { + float pageOffset = pdfView.pdfFile.getPageOffset(page, pdfView.getZoom()); + + if (pdfView.isSwipeVertical()) { + pageFirstXOffset = fixedFirstXOffset; + pageFirstYOffset = pageOffset; + } else { + pageFirstYOffset = fixedFirstYOffset; + pageFirstXOffset = pageOffset; + } - for (int i = firstHolder.page; i <= lastHolder.page; i++) { - loadThumbnail(i); - } + pageLastXOffset = fixedLastXOffset; + pageLastYOffset = fixedLastYOffset; - int pagesCount = lastHolder.page - firstHolder.page + 1; - for (int page = firstHolder.page; page <= lastHolder.page && parts < CACHE_SIZE; page++) { + } else { + float pageOffset = pdfView.pdfFile.getPageOffset(page, pdfView.getZoom()); + SizeF pageSize = pdfView.pdfFile.getScaledPageSize(page, pdfView.getZoom()); + if (pdfView.isSwipeVertical()) { + pageFirstXOffset = fixedFirstXOffset; + pageFirstYOffset = pageOffset; + + pageLastXOffset = fixedLastXOffset; + pageLastYOffset = pageOffset + pageSize.getHeight(); + } else { + pageFirstXOffset = pageOffset; + pageFirstYOffset = fixedFirstYOffset; + + pageLastXOffset = pageOffset + pageSize.getWidth(); + pageLastYOffset = fixedLastYOffset; + } + } + + getPageColsRows(range.gridSize, range.page); // get the page's grid size that rows and cols + SizeF scaledPageSize = pdfView.pdfFile.getScaledPageSize(range.page, pdfView.getZoom()); + float rowHeight = scaledPageSize.getHeight() / range.gridSize.rows; + float colWidth = scaledPageSize.getWidth() / range.gridSize.cols; + + + // get the page offset int the whole file + // --------------------------------------- + // | | | | + // |<--offset-->| (page) |<--offset-->| + // | | | | + // | | | | + // --------------------------------------- + float secondaryOffset = pdfView.pdfFile.getSecondaryPageOffset(page, pdfView.getZoom()); + + // calculate the row,col of the point in the leftTop and rightBottom + if (pdfView.isSwipeVertical()) { + range.leftTop.row = MathUtils.floor(Math.abs(pageFirstYOffset - pdfView.pdfFile.getPageOffset(range.page, pdfView.getZoom())) / rowHeight); + range.leftTop.col = MathUtils.floor(MathUtils.min(pageFirstXOffset - secondaryOffset, 0) / colWidth); - if (page == firstHolder.page && pagesCount > 1) { - parts += loadPageEnd(firstHolder, firstGrid, CACHE_SIZE - parts); - } else if (page == lastHolder.page && pagesCount > 1) { - parts += loadPageStart(lastHolder, lastGrid, CACHE_SIZE - parts); - } else if(pagesCount == 1) { - parts += loadPageCenter(firstHolder, lastHolder, firstGrid, CACHE_SIZE - parts); + range.rightBottom.row = MathUtils.ceil(Math.abs(pageLastYOffset - pdfView.pdfFile.getPageOffset(range.page, pdfView.getZoom())) / rowHeight); + range.rightBottom.col = MathUtils.floor(MathUtils.min(pageLastXOffset - secondaryOffset, 0) / colWidth); } else { - getPageColsRows(middleGrid, page); - parts += loadWholePage(page, middleGrid, CACHE_SIZE - parts); + range.leftTop.col = MathUtils.floor(Math.abs(pageFirstXOffset - pdfView.pdfFile.getPageOffset(range.page, pdfView.getZoom())) / colWidth); + range.leftTop.row = MathUtils.floor(MathUtils.min(pageFirstYOffset - secondaryOffset, 0) / rowHeight); + + range.rightBottom.col = MathUtils.floor(Math.abs(pageLastXOffset - pdfView.pdfFile.getPageOffset(range.page, pdfView.getZoom())) / colWidth); + range.rightBottom.row = MathUtils.floor(MathUtils.min(pageLastYOffset - secondaryOffset, 0) / rowHeight); } + + renderRanges.add(range); } + return renderRanges; } - /** - * When whole page is visible - * - * @return loaded parts count - */ - private int loadWholePage(int page, GridSize grid, int nbOfPartsLoadable) { - calculatePartSize(grid); - return loadPage(page, 0, grid.rows - 1, 0, grid.cols - 1, nbOfPartsLoadable); - } + private void loadVisible() { + int parts = 0; + float scaledPreloadOffset = preloadOffset; + float firstXOffset = -xOffset + scaledPreloadOffset; + float lastXOffset = -xOffset - pdfView.getWidth() - scaledPreloadOffset; + float firstYOffset = -yOffset + scaledPreloadOffset; + float lastYOffset = -yOffset - pdfView.getHeight() - scaledPreloadOffset; - /** - * When only part of one page is visible - * - * @return loaded parts count - */ - private int loadPageCenter(Holder firstHolder, Holder lastHolder, GridSize grid, int nbOfPartsLoadable) { - calculatePartSize(grid); - return loadPage(firstHolder.page, firstHolder.row, lastHolder.row, firstHolder.col, lastHolder.col, nbOfPartsLoadable); - } + List rangeList = getRenderRangeList(firstXOffset, firstYOffset, lastXOffset, lastYOffset); - /** - * When only end of page is visible - * - * @return loaded parts count - */ - private int loadPageEnd(Holder holder, GridSize grid, int nbOfPartsLoadable) { - calculatePartSize(grid); - if (pdfView.isSwipeVertical()) { - int firstRow = holder.row; - return loadPage(holder.page, firstRow, grid.rows - 1, 0, grid.cols - 1, nbOfPartsLoadable); - } else { - int firstCol = holder.col; - return loadPage(holder.page, 0, grid.rows - 1, firstCol, grid.cols - 1, nbOfPartsLoadable); + for (RenderRange range : rangeList) { + loadThumbnail(range.page); } - } - /** - * If only start of the page is visible - * - * @return loaded parts count - */ - private int loadPageStart(Holder holder, GridSize grid, int nbOfPartsLoadable) { - calculatePartSize(grid); - if (pdfView.isSwipeVertical()) { - int lastRow = holder.row; - return loadPage(holder.page, 0, lastRow, 0, grid.cols - 1, nbOfPartsLoadable); - } else { - int lastCol = holder.col; - return loadPage(holder.page, 0, grid.rows - 1, 0, lastCol, nbOfPartsLoadable); + for (RenderRange range : rangeList) { + calculatePartSize(range.gridSize); + parts += loadPage(range.page, range.leftTop.row, range.rightBottom.row, range.leftTop.col, range.rightBottom.col, CACHE_SIZE - parts); + if (parts >= CACHE_SIZE) { + break; + } } } diff --git a/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/PdfFile.java b/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/PdfFile.java index f40d29ed..fdc104f2 100644 --- a/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/PdfFile.java +++ b/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/PdfFile.java @@ -52,9 +52,9 @@ class PdfFile { /** Scaled page with maximum width */ private SizeF maxWidthPageSize = new SizeF(0, 0); /** True if scrolling is vertical, else it's horizontal */ - private boolean isVertical = true; + private boolean isVertical; /** Fixed spacing between pages in pixels */ - private int spacingPx = 0; + private int spacingPx; /** Calculate spacing automatically so each page fits on it's own in the center of the view */ private boolean autoSpacing; /** Calculated offsets for pages */ @@ -64,6 +64,11 @@ class PdfFile { /** Calculated document length (width or height, depending on swipe mode) */ private float documentLength = 0; private final FitPolicy pageFitPolicy; + /** + * True if every page should fit separately according to the FitPolicy, + * else the largest page fits and other pages scale relatively + */ + private final boolean fitEachPage; /** * The pages the user want to display in order * (ex: 0, 2, 2, 8, 8, 1, 1, 1) @@ -71,7 +76,7 @@ class PdfFile { private int[] originalUserPages; PdfFile(PdfiumCore pdfiumCore, PdfDocument pdfDocument, FitPolicy pageFitPolicy, Size viewSize, int[] originalUserPages, - boolean isVertical, int spacing, boolean autoSpacing) { + boolean isVertical, int spacing, boolean autoSpacing, boolean fitEachPage) { this.pdfiumCore = pdfiumCore; this.pdfDocument = pdfDocument; this.pageFitPolicy = pageFitPolicy; @@ -79,6 +84,7 @@ class PdfFile { this.isVertical = isVertical; this.spacingPx = spacing; this.autoSpacing = autoSpacing; + this.fitEachPage = fitEachPage; setup(viewSize); } @@ -111,7 +117,7 @@ private void setup(Size viewSize) { public void recalculatePageSizes(Size viewSize) { pageSizes.clear(); PageSizeCalculator calculator = new PageSizeCalculator(pageFitPolicy, originalMaxWidthPageSize, - originalMaxHeightPageSize, viewSize); + originalMaxHeightPageSize, viewSize, fitEachPage); maxWidthPageSize = calculator.getOptimalMaxWidthPageSize(); maxHeightPageSize = calculator.getOptimalMaxHeightPageSize(); diff --git a/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/scroll/DefaultScrollHandle.java b/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/scroll/DefaultScrollHandle.java index 81b9956b..8195a540 100644 --- a/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/scroll/DefaultScrollHandle.java +++ b/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/scroll/DefaultScrollHandle.java @@ -110,7 +110,9 @@ public void setScroll(float position) { } else { handler.removeCallbacks(hidePageScrollerRunnable); } - setPosition((pdfView.isSwipeVertical() ? pdfView.getHeight() : pdfView.getWidth()) * position); + if (pdfView != null) { + setPosition((pdfView.isSwipeVertical() ? pdfView.getHeight() : pdfView.getWidth()) * position); + } } private void setPosition(float pos) { diff --git a/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/util/PageSizeCalculator.java b/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/util/PageSizeCalculator.java index 02992a21..4d678c98 100644 --- a/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/util/PageSizeCalculator.java +++ b/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/util/PageSizeCalculator.java @@ -28,13 +28,15 @@ public class PageSizeCalculator { private SizeF optimalMaxHeightPageSize; private float widthRatio; private float heightRatio; + private boolean fitEachPage; public PageSizeCalculator(FitPolicy fitPolicy, Size originalMaxWidthPageSize, Size originalMaxHeightPageSize, - Size viewSize) { + Size viewSize, boolean fitEachPage) { this.fitPolicy = fitPolicy; this.originalMaxWidthPageSize = originalMaxWidthPageSize; this.originalMaxHeightPageSize = originalMaxHeightPageSize; this.viewSize = viewSize; + this.fitEachPage = fitEachPage; calculateMaxPages(); } @@ -42,13 +44,15 @@ public SizeF calculate(Size pageSize) { if (pageSize.getWidth() <= 0 || pageSize.getHeight() <= 0) { return new SizeF(0, 0); } + float maxWidth = fitEachPage ? viewSize.getWidth() : pageSize.getWidth() * widthRatio; + float maxHeight = fitEachPage ? viewSize.getHeight() : pageSize.getHeight() * heightRatio; switch (fitPolicy) { case HEIGHT: - return fitHeight(pageSize, pageSize.getHeight() * heightRatio); + return fitHeight(pageSize, maxHeight); case BOTH: - return fitBoth(pageSize, pageSize.getWidth() * widthRatio, pageSize.getHeight() * heightRatio); + return fitBoth(pageSize, maxWidth, maxHeight); default: - return fitWidth(pageSize, pageSize.getWidth() * widthRatio); + return fitWidth(pageSize, maxWidth); } } diff --git a/build.gradle b/build.gradle index a40f1b28..0a9a0ba0 100644 --- a/build.gradle +++ b/build.gradle @@ -5,8 +5,8 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.1.3' - classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.1' + classpath 'com.android.tools.build:gradle:3.4.2' + classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4' classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1' } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 8fc5b9c1..1a59b22b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Wed Jun 27 20:37:56 CEST 2018 +#Sun Aug 18 01:14:14 CEST 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip diff --git a/sample/build.gradle b/sample/build.gradle index 5b0fb37e..133bcdde 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -13,11 +13,11 @@ repositories { apply plugin: 'com.android.application' android { - compileSdkVersion 26 + compileSdkVersion 28 defaultConfig { minSdkVersion 14 - targetSdkVersion 26 + targetSdkVersion 28 versionCode 3 versionName "3.0.0" } @@ -26,7 +26,7 @@ android { dependencies { implementation project(':android-pdf-viewer') - implementation 'com.android.support:appcompat-v7:26.1.0' - implementation 'org.androidannotations:androidannotations-api:4.4.0' - annotationProcessor "org.androidannotations:androidannotations:4.4.0" + implementation 'com.android.support:appcompat-v7:28.0.0' + implementation 'org.androidannotations:androidannotations-api:4.6.0' + annotationProcessor "org.androidannotations:androidannotations:4.6.0" }