Skip to content
This repository was archived by the owner on Nov 10, 2025. It is now read-only.

Commit 499ffbc

Browse files
committed
Add handling page load error
Add support for working inside SwipeRefreshLayout Fix bug when document was loaded before view's measurement Update PdfiumAndroid Update README and CHANGELOG Update version
1 parent 69f7398 commit 499ffbc

File tree

8 files changed

+202
-36
lines changed

8 files changed

+202
-36
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## 2.8.0 (2017-10-31)
2+
* Add handling of invalid pages, inspired by pull request #433. Exception on page opening crashed application until now,
3+
currently `OnPageErrorListener` set with `.onPageError()` is called. Invalid page color can be set using `.invalidPageColor()`
4+
* Implement `canScrollVertically()` and `canScrollHorizontally()` methods to work e.g. with `SwipeRefreshLayout`
5+
* Fix bug when `Configurator#load()` method was called before view has been measured, which resulted in empty canvas
6+
17
## 2.7.0 (2017-08-30)
28
* Merge pull request by [owurman](https://github.com/owurman) with added OnTapListener
39
* Merge bugfix by [lzwandnju](https://github.com/lzwandnju) to prevent `ArithmeticException: divide by zero`

README.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@ Library for displaying PDF documents on Android, with `animations`, `gestures`,
1010
It is based on [PdfiumAndroid](https://github.com/barteksc/PdfiumAndroid) for decoding PDF files. Works on API 11 (Android 3.0) and higher.
1111
Licensed under Apache License 2.0.
1212

13-
## What's new in 2.7.0?
14-
* Merge pull request by [owurman](https://github.com/owurman) with added OnTapListener
15-
* Merge bugfix by [lzwandnju](https://github.com/lzwandnju) to prevent `ArithmeticException: divide by zero`
13+
## What's new in 2.8.0?
14+
* Add handling of invalid pages, inspired by pull request #433. Exception on page opening crashed application until now,
15+
currently `OnPageErrorListener` set with `Configurator#onPageError()` is called. Invalid page color (`Color` class) can be set using `Configurator#invalidPageColor()`
16+
* Implement `canScrollVertically()` and `canScrollHorizontally()` methods to work e.g. with `SwipeRefreshLayout`
17+
* Fix bug when `Configurator#load()` method was called before view has been measured, which resulted in empty canvas
1618

1719
## Changes in 2.0 API
1820
* `Configurator#defaultPage(int)` and `PDFView#jumpTo(int)` now require page index (i.e. starting from 0)
@@ -27,7 +29,7 @@ Licensed under Apache License 2.0.
2729

2830
Add to _build.gradle_:
2931

30-
`compile 'com.github.barteksc:android-pdf-viewer:2.7.0'`
32+
`compile 'com.github.barteksc:android-pdf-viewer:2.8.0'`
3133

3234
Library is available in jcenter repository, probably it'll be in Maven Central soon.
3335

@@ -68,6 +70,7 @@ pdfView.fromAsset(String)
6870
.onPageChange(onPageChangeListener)
6971
.onPageScroll(onPageScrollListener)
7072
.onError(onErrorListener)
73+
.onPageError(onPageErrorListener)
7174
.onRender(onRenderListener) // called after document is rendered for the first time
7275
// called on single tap, return true if handled, false to toggle scroll handle visibility
7376
.onTap(onTapListener)
@@ -76,7 +79,8 @@ pdfView.fromAsset(String)
7679
.scrollHandle(null)
7780
.enableAntialiasing(true) // improve rendering a little bit on low-res screens
7881
// spacing between pages in dp. To define spacing color, set view background
79-
.spacing(0)
82+
.spacing(0)
83+
.invalidPageColor(Color.WHITE) // color of page that is invalid and cannot be loaded
8084
.load();
8185
```
8286

android-pdf-viewer/build.gradle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ ext {
1313
siteUrl = 'https://github.com/barteksc/AndroidPdfViewer'
1414
gitUrl = 'https://github.com/barteksc/AndroidPdfViewer.git'
1515

16-
libraryVersion = '2.7.0'
16+
libraryVersion = '2.8.0'
1717

1818
developerId = 'barteksc'
1919
developerName = 'Bartosz Schiller'
@@ -32,13 +32,13 @@ android {
3232
minSdkVersion 11
3333
targetSdkVersion 25
3434
versionCode 1
35-
versionName "2.7.0"
35+
versionName "2.8.0"
3636
}
3737

3838
}
3939

4040
dependencies {
41-
compile 'com.github.barteksc:pdfium-android:1.7.0'
41+
compile 'com.github.barteksc:pdfium-android:1.7.1'
4242
}
4343

4444
apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/installv1.gradle'

android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/PDFView.java

Lines changed: 95 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@
3333
import android.util.Log;
3434
import android.widget.RelativeLayout;
3535

36+
import com.github.barteksc.pdfviewer.exception.PageRenderingException;
3637
import com.github.barteksc.pdfviewer.listener.OnDrawListener;
3738
import com.github.barteksc.pdfviewer.listener.OnErrorListener;
3839
import com.github.barteksc.pdfviewer.listener.OnLoadCompleteListener;
3940
import com.github.barteksc.pdfviewer.listener.OnPageChangeListener;
41+
import com.github.barteksc.pdfviewer.listener.OnPageErrorListener;
4042
import com.github.barteksc.pdfviewer.listener.OnPageScrollListener;
4143
import com.github.barteksc.pdfviewer.listener.OnRenderListener;
4244
import com.github.barteksc.pdfviewer.listener.OnTapListener;
@@ -238,6 +240,11 @@ enum ScrollDir {
238240
*/
239241
private OnTapListener onTapListener;
240242

243+
/**
244+
* Call back object to call when the page load error occurs
245+
*/
246+
private OnPageErrorListener onPageErrorListener;
247+
241248
/**
242249
* Paint object for drawing
243250
*/
@@ -248,6 +255,11 @@ enum ScrollDir {
248255
*/
249256
private Paint debugPaint;
250257

258+
/**
259+
* Paint used for invalid pages
260+
*/
261+
private int invalidPageColor = Color.WHITE;
262+
251263
private int defaultPage = 0;
252264

253265
/**
@@ -527,6 +539,18 @@ private void setOnDrawAllListener(OnDrawListener onDrawAllListener) {
527539
this.onDrawAllListener = onDrawAllListener;
528540
}
529541

542+
private void setOnPageErrorListener(OnPageErrorListener onPageErrorListener) {
543+
this.onPageErrorListener = onPageErrorListener;
544+
}
545+
546+
void onPageError(PageRenderingException ex) {
547+
if (onPageErrorListener != null) {
548+
onPageErrorListener.onPageError(ex.getPage(), ex.getCause());
549+
} else {
550+
Log.e(TAG, "Cannot open page " + ex.getPage(), ex.getCause());
551+
}
552+
}
553+
530554
public void recycle() {
531555

532556
animationManager.stopAll();
@@ -598,6 +622,42 @@ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
598622
loadPageByOffset();
599623
}
600624

625+
@Override
626+
public boolean canScrollHorizontally(int direction) {
627+
if (swipeVertical) {
628+
if (direction < 0 && currentXOffset < 0) {
629+
return true;
630+
} else if (direction > 0 && currentXOffset + toCurrentScale(optimalPageWidth) > getWidth()) {
631+
return true;
632+
}
633+
} else {
634+
if (direction < 0 && currentXOffset < 0) {
635+
return true;
636+
} else if (direction > 0 && currentXOffset + calculateDocLength() > getWidth()) {
637+
return true;
638+
}
639+
}
640+
return false;
641+
}
642+
643+
@Override
644+
public boolean canScrollVertically(int direction) {
645+
if (swipeVertical) {
646+
if (direction < 0 && currentYOffset < 0) {
647+
return true;
648+
} else if (direction > 0 && currentYOffset + calculateDocLength() > getHeight()) {
649+
return true;
650+
}
651+
} else {
652+
if (direction < 0 && currentYOffset < 0) {
653+
return true;
654+
} else if (direction > 0 && currentYOffset + toCurrentScale(optimalPageHeight) > getHeight()) {
655+
return true;
656+
}
657+
}
658+
return false;
659+
}
660+
601661
@Override
602662
protected void onDraw(Canvas canvas) {
603663
if (isInEditMode()) {
@@ -1275,6 +1335,14 @@ private void setSpacing(int spacing) {
12751335
this.spacingPx = Util.getDP(getContext(), spacing);
12761336
}
12771337

1338+
private void setInvalidPageColor(int invalidPageColor) {
1339+
this.invalidPageColor = invalidPageColor;
1340+
}
1341+
1342+
public int getInvalidPageColor() {
1343+
return invalidPageColor;
1344+
}
1345+
12781346
public boolean doRenderDuringScale() {
12791347
return renderDuringScale;
12801348
}
@@ -1363,6 +1431,8 @@ public class Configurator {
13631431

13641432
private OnTapListener onTapListener;
13651433

1434+
private OnPageErrorListener onPageErrorListener;
1435+
13661436
private int defaultPage = 0;
13671437

13681438
private boolean swipeHorizontal = false;
@@ -1377,6 +1447,8 @@ public class Configurator {
13771447

13781448
private int spacing = 0;
13791449

1450+
private int invalidPageColor = Color.WHITE;
1451+
13801452
private Configurator(DocumentSource documentSource) {
13811453
this.documentSource = documentSource;
13821454
}
@@ -1426,6 +1498,11 @@ public Configurator onError(OnErrorListener onErrorListener) {
14261498
return this;
14271499
}
14281500

1501+
public Configurator onPageError(OnPageErrorListener onPageErrorListener) {
1502+
this.onPageErrorListener = onPageErrorListener;
1503+
return this;
1504+
}
1505+
14291506
public Configurator onPageChange(OnPageChangeListener onPageChangeListener) {
14301507
this.onPageChangeListener = onPageChangeListener;
14311508
return this;
@@ -1471,6 +1548,11 @@ public Configurator spacing(int spacing) {
14711548
return this;
14721549
}
14731550

1551+
public Configurator invalidPageColor(int invalidPageColor) {
1552+
this.invalidPageColor = invalidPageColor;
1553+
return this;
1554+
}
1555+
14741556
public void load() {
14751557
PDFView.this.recycle();
14761558
PDFView.this.setOnDrawListener(onDrawListener);
@@ -1479,6 +1561,7 @@ public void load() {
14791561
PDFView.this.setOnPageScrollListener(onPageScrollListener);
14801562
PDFView.this.setOnRenderListener(onRenderListener);
14811563
PDFView.this.setOnTapListener(onTapListener);
1564+
PDFView.this.setOnPageErrorListener(onPageErrorListener);
14821565
PDFView.this.enableSwipe(enableSwipe);
14831566
PDFView.this.enableDoubletap(enableDoubletap);
14841567
PDFView.this.setDefaultPage(defaultPage);
@@ -1487,12 +1570,19 @@ public void load() {
14871570
PDFView.this.setScrollHandle(scrollHandle);
14881571
PDFView.this.enableAntialiasing(antialiasing);
14891572
PDFView.this.setSpacing(spacing);
1573+
PDFView.this.setInvalidPageColor(invalidPageColor);
14901574
PDFView.this.dragPinchManager.setSwipeVertical(swipeVertical);
1491-
if (pageNumbers != null) {
1492-
PDFView.this.load(documentSource, password, onLoadCompleteListener, onErrorListener, pageNumbers);
1493-
} else {
1494-
PDFView.this.load(documentSource, password, onLoadCompleteListener, onErrorListener);
1495-
}
1575+
1576+
PDFView.this.post(new Runnable() {
1577+
@Override
1578+
public void run() {
1579+
if (pageNumbers != null) {
1580+
PDFView.this.load(documentSource, password, onLoadCompleteListener, onErrorListener, pageNumbers);
1581+
} else {
1582+
PDFView.this.load(documentSource, password, onLoadCompleteListener, onErrorListener);
1583+
}
1584+
}
1585+
});
14961586
}
14971587
}
14981588
}

android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/RenderingHandler.java

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,13 @@
2222
import android.os.Handler;
2323
import android.os.Looper;
2424
import android.os.Message;
25+
import android.util.SparseBooleanArray;
2526

27+
import com.github.barteksc.pdfviewer.exception.PageRenderingException;
2628
import com.github.barteksc.pdfviewer.model.PagePart;
2729
import com.shockwave.pdfium.PdfDocument;
2830
import com.shockwave.pdfium.PdfiumCore;
2931

30-
import java.util.HashSet;
31-
import java.util.Set;
32-
3332
/**
3433
* A {@link Handler} that will process incoming {@link RenderingTask} messages
3534
* and alert {@link PDFView#onBitmapRendered(PagePart)} when the portion of the
@@ -41,6 +40,8 @@ class RenderingHandler extends Handler {
4140
*/
4241
static final int MSG_RENDER_TASK = 1;
4342

43+
private static final String TAG = RenderingHandler.class.getName();
44+
4445
private PdfiumCore pdfiumCore;
4546
private PdfDocument pdfDocument;
4647

@@ -49,7 +50,7 @@ class RenderingHandler extends Handler {
4950
private RectF renderBounds = new RectF();
5051
private Rect roundedRenderBounds = new Rect();
5152
private Matrix renderMatrix = new Matrix();
52-
private final Set<Integer> openedPages = new HashSet<>();
53+
private final SparseBooleanArray openedPages = new SparseBooleanArray();
5354
private boolean running = false;
5455

5556
RenderingHandler(Looper looper, PDFView pdfView, PdfiumCore pdfiumCore, PdfDocument pdfDocument) {
@@ -68,25 +69,39 @@ void addRenderingTask(int userPage, int page, float width, float height, RectF b
6869
@Override
6970
public void handleMessage(Message message) {
7071
RenderingTask task = (RenderingTask) message.obj;
71-
final PagePart part = proceed(task);
72-
if (part != null) {
73-
if (running) {
74-
pdfView.post(new Runnable() {
75-
@Override
76-
public void run() {
77-
pdfView.onBitmapRendered(part);
78-
}
79-
});
80-
} else {
81-
part.getRenderedBitmap().recycle();
72+
try {
73+
final PagePart part = proceed(task);
74+
if (part != null) {
75+
if (running) {
76+
pdfView.post(new Runnable() {
77+
@Override
78+
public void run() {
79+
pdfView.onBitmapRendered(part);
80+
}
81+
});
82+
} else {
83+
part.getRenderedBitmap().recycle();
84+
}
8285
}
86+
} catch (final PageRenderingException ex) {
87+
pdfView.post(new Runnable() {
88+
@Override
89+
public void run() {
90+
pdfView.onPageError(ex);
91+
}
92+
});
8393
}
8494
}
8595

86-
private PagePart proceed(RenderingTask renderingTask) {
87-
if (!openedPages.contains(renderingTask.page)) {
88-
openedPages.add(renderingTask.page);
89-
pdfiumCore.openPage(pdfDocument, renderingTask.page);
96+
private PagePart proceed(RenderingTask renderingTask) throws PageRenderingException {
97+
if (openedPages.indexOfKey(renderingTask.page) < 0) {
98+
try {
99+
pdfiumCore.openPage(pdfDocument, renderingTask.page);
100+
openedPages.put(renderingTask.page, true);
101+
} catch (Exception e) {
102+
openedPages.put(renderingTask.page, false);
103+
throw new PageRenderingException(renderingTask.page, e);
104+
}
90105
}
91106

92107
int w = Math.round(renderingTask.width);
@@ -99,10 +114,14 @@ private PagePart proceed(RenderingTask renderingTask) {
99114
return null;
100115
}
101116
calculateBounds(w, h, renderingTask.bounds);
102-
pdfiumCore.renderPageBitmap(pdfDocument, render, renderingTask.page,
103-
roundedRenderBounds.left, roundedRenderBounds.top,
104-
roundedRenderBounds.width(), roundedRenderBounds.height(), renderingTask.annotationRendering);
117+
if (openedPages.get(renderingTask.page)) {
105118

119+
pdfiumCore.renderPageBitmap(pdfDocument, render, renderingTask.page,
120+
roundedRenderBounds.left, roundedRenderBounds.top,
121+
roundedRenderBounds.width(), roundedRenderBounds.height(), renderingTask.annotationRendering);
122+
} else {
123+
render.eraseColor(pdfView.getInvalidPageColor());
124+
}
106125
return new PagePart(renderingTask.userPage, renderingTask.page, render,
107126
renderingTask.width, renderingTask.height,
108127
renderingTask.bounds, renderingTask.thumbnail,
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.github.barteksc.pdfviewer.exception;
2+
3+
public class PageRenderingException extends Exception {
4+
private final int page;
5+
6+
public PageRenderingException(int page, Throwable cause) {
7+
super(cause);
8+
this.page = page;
9+
}
10+
11+
public int getPage() {
12+
return page;
13+
}
14+
}

0 commit comments

Comments
 (0)