Showing preview only (244K chars total). Download the full file or copy to clipboard to get everything.
Repository: DImuthuUpe/AndroidPdfViewer
Branch: master
Commit: e62698bebb24
Files: 67
Total size: 222.4 KB
Directory structure:
gitextract_l2u_xl7x/
├── .gitignore
├── 16KB_SUPPORT.md
├── CHANGELOG.md
├── LICENSE
├── README.md
├── android-pdf-viewer/
│ ├── bintray.gradle
│ ├── build.gradle
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ ├── java/
│ │ └── com/
│ │ └── github/
│ │ └── barteksc/
│ │ └── pdfviewer/
│ │ ├── AnimationManager.java
│ │ ├── CacheManager.java
│ │ ├── DecodingAsyncTask.java
│ │ ├── DragPinchManager.java
│ │ ├── PDFView.java
│ │ ├── PagesLoader.java
│ │ ├── PdfFile.java
│ │ ├── RenderingHandler.java
│ │ ├── exception/
│ │ │ ├── FileNotFoundException.java
│ │ │ └── PageRenderingException.java
│ │ ├── link/
│ │ │ ├── DefaultLinkHandler.java
│ │ │ └── LinkHandler.java
│ │ ├── listener/
│ │ │ ├── Callbacks.java
│ │ │ ├── OnDrawListener.java
│ │ │ ├── OnErrorListener.java
│ │ │ ├── OnLoadCompleteListener.java
│ │ │ ├── OnLongPressListener.java
│ │ │ ├── OnPageChangeListener.java
│ │ │ ├── OnPageErrorListener.java
│ │ │ ├── OnPageScrollListener.java
│ │ │ ├── OnRenderListener.java
│ │ │ └── OnTapListener.java
│ │ ├── model/
│ │ │ ├── LinkTapEvent.java
│ │ │ └── PagePart.java
│ │ ├── scroll/
│ │ │ ├── DefaultScrollHandle.java
│ │ │ └── ScrollHandle.java
│ │ ├── source/
│ │ │ ├── AssetSource.java
│ │ │ ├── ByteArraySource.java
│ │ │ ├── DocumentSource.java
│ │ │ ├── FileSource.java
│ │ │ ├── InputStreamSource.java
│ │ │ └── UriSource.java
│ │ └── util/
│ │ ├── ArrayUtils.java
│ │ ├── Constants.java
│ │ ├── FileUtils.java
│ │ ├── FitPolicy.java
│ │ ├── MathUtils.java
│ │ ├── PageSizeCalculator.java
│ │ ├── SnapEdge.java
│ │ └── Util.java
│ └── res/
│ ├── drawable/
│ │ ├── default_scroll_handle_bottom.xml
│ │ ├── default_scroll_handle_left.xml
│ │ ├── default_scroll_handle_right.xml
│ │ └── default_scroll_handle_top.xml
│ └── values/
│ └── attrs.xml
├── build.gradle
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── sample/
│ ├── build.gradle
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ ├── java/
│ │ └── com/
│ │ └── github/
│ │ └── barteksc/
│ │ └── sample/
│ │ └── PDFViewActivity.java
│ └── res/
│ ├── layout/
│ │ └── activity_main.xml
│ ├── menu/
│ │ └── options.xml
│ └── values/
│ ├── strings.xml
│ └── styles.xml
└── settings.gradle
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
target/
build/
lint.xml
bin/
gen/
.settings
.project
.classpath
out
gen-external-apklibs/
classes/
# Local configuration file (sdk path, etc)
local.properties
# Android Studio
.idea/
*/out
!*/build/apk/
*/production/
*.iws
*.ipr
*.iml
*~
*.swp
# gradle
.gradle
.DS_Store
================================================
FILE: 16KB_SUPPORT.md
================================================
# 16 KB Page Size Support
This Android PDF Viewer library has been updated to support 16 KB page sizes, which is required for Google Play compatibility starting November 1st, 2025.
## What Changed
### Build Configuration Updates
1. **Android Gradle Plugin**: Already using AGP 8.13.0 (✅ above required 8.5.1)
2. **NDK Version**: Updated to use NDK r28+ for 16 KB support
3. **Packaging Options**: Configured to use uncompressed shared libraries for proper 16 KB alignment
4. **Gradle Properties**: Added configuration for 16 KB compatibility
### Key Changes Made
#### android-pdf-viewer/build.gradle
```gradle
// 16 KB page size support configuration
packagingOptions {
jniLibs {
useLegacyPackaging false // Use uncompressed shared libraries for 16 KB alignment
}
}
// Enable 16 KB page size support for native libraries
ndkVersion "28.0.12433566" // Use NDK r28+ for 16 KB support
```
#### sample/build.gradle
```gradle
packagingOptions {
// ... existing exclusions ...
// 16 KB page size support configuration
jniLibs {
useLegacyPackaging false // Use uncompressed shared libraries for 16 KB alignment
}
}
// Enable 16 KB page size support for native libraries
ndkVersion "28.0.12433566" // Use NDK r28+ for 16 KB support
```
#### gradle.properties
```properties
# 16 KB page size support
android.bundle.enableUncompressedNativeLibs=false
android.enableR8.fullMode=true
```
## Native Dependencies
This library uses `pdfium-android:1.9.0`, which contains native libraries. The configuration ensures these libraries are properly aligned for 16 KB page sizes.
## Verification
### Using the Provided Scripts
#### Linux/macOS
```bash
./check_16kb_alignment.sh sample/build/outputs/apk/debug/sample-debug.apk
```
#### Windows PowerShell
```powershell
.\check_16kb_alignment.ps1 -ApkFile "sample\build\outputs\apk\debug\sample-debug.apk"
```
#### Windows Batch Script
```batch
.\realign_apk.bat "sample\build\outputs\apk\debug\sample-debug.apk"
```
#### Python Script (Cross-platform)
```bash
python fix_16kb_alignment.py "sample/build/outputs/apk/debug/sample-debug.apk"
```
### Manual Verification
1. **Check APK alignment**:
```bash
zipalign -c -p -v 4 your-app.apk
```
2. **Test on 16 KB device**:
```bash
adb shell getconf PAGE_SIZE
# Should return 16384
```
### Fixing Alignment Issues
If your APK fails 16 KB alignment checks, use the provided realignment scripts:
1. **Copy your APK** to avoid file lock issues:
```bash
cp sample/build/outputs/apk/debug/sample-debug.apk sample-debug-copy.apk
```
2. **Run the realignment script**:
```bash
.\realign_apk.bat "sample-debug-copy.apk"
```
3. **Verify the fix**:
```bash
zipalign -c -p -v 4 sample-debug-copy.apk
```
## Testing on 16 KB Devices
### Android Emulator
1. Download Android 15 system image with 16 KB page size support
2. Create virtual device with the 16 KB system image
3. Test your app on the emulator
### Physical Devices
- Pixel 8 and 8 Pro (Android 15 QPR1+)
- Pixel 8a (Android 15 QPR1+)
- Pixel 9, 9 Pro, and 9 Pro XL (Android 15 QPR2 Beta 2+)
Enable "Boot with 16KB page size" in Developer Options.
## Benefits
Devices with 16 KB page sizes provide:
- 3.16% lower app launch times on average
- 4.56% reduction in power draw during app launch
- 4.48% faster camera launch (hot starts)
- 6.60% faster camera launch (cold starts)
- 8% improved system boot time
## Compatibility
- ✅ **AGP Version**: 8.13.0 (above required 8.5.1)
- ✅ **NDK Version**: r28+ (16 KB aligned by default)
- ✅ **Native Libraries**: Configured for 16 KB alignment
- ✅ **Packaging**: Uncompressed shared libraries for proper alignment
## Resources
- [Android 16 KB Page Size Guide](https://developer.android.com/guide/practices/page-sizes)
- [Google Play 16 KB Requirement](https://android-developers.googleblog.com/2025/05/prepare-play-apps-for-devices-with-16kb-page-size.html)
- [APK Analyzer Tool](https://developer.android.com/studio/build/analyze-apk)
## Troubleshooting
If you encounter issues:
1. **Verify NDK version**: Ensure you're using NDK r28 or higher
2. **Check AGP version**: Must be 8.5.1 or higher
3. **Run alignment check**: Use the provided scripts to verify APK alignment
4. **Test on 16 KB device**: Use emulator or physical device with 16 KB support
## Support
For issues related to 16 KB page size support, please check:
1. The alignment verification scripts
2. Android Studio's APK Analyzer
3. The official Android documentation linked above
================================================
FILE: CHANGELOG.md
================================================
## 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
* 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
## 3.0.0-beta.5 (2018-01-06)
* Fix issue with `Configurator#pages()` from #486
* Fix `IllegalStateException` from #464
* Fix not detecting links reported in #447
## 3.0.0-beta.4 (2017-12-15)
* Fix not loaded pages when using animated `PDFView#jumpTo()`
* Fix NPE in `canScrollVertically()` and `canScrollHorizontally()`
## 3.0.0-beta.3 (2017-11-18)
* Fix bug preventing `OnErrorListener` from being called
## 3.0.0-beta.2 (2017-11-15)
* Fix rendering with maximum zoom
* Improve fit policies
* Update PdfiumAndroid to 1.8.1
## 3.0.0-beta.1 (2017-11-12)
* Add support for documents with different page sizes
* Add support for links
* Add support for defining page fit policy (fit width, height or both)
* Update sample.pdf to contain different page sizes
## 2.8.1 (2017-11-11)
* Fix bug with rendering `PDFView` in Android Studio Layout Editor
## 2.8.0 (2017-10-31)
* Add handling of invalid pages, inspired by pull request #433. Exception on page opening crashed application until now,
currently `OnPageErrorListener` set with `.onPageError()` is called. Invalid page color can be set using `.invalidPageColor()`
* Implement `canScrollVertically()` and `canScrollHorizontally()` methods to work e.g. with `SwipeRefreshLayout`
* Fix bug when `Configurator#load()` method was called before view has been measured, which resulted in empty canvas
## 2.7.0 (2017-08-30)
* Merge pull request by [owurman](https://github.com/owurman) with added OnTapListener
* Merge bugfix by [lzwandnju](https://github.com/lzwandnju) to prevent `ArithmeticException: divide by zero`
## 2.7.0-beta.1 (2017-07-05)
* Updates PdfiumAndroid to 1.7.0 which reduces memory usage about twice and improves performance by using RGB 565 format (when not using `pdfView.useBestQuality(true)`)
## 2.7.0-beta (2017-06-16)
* Update PdfiumAndroid to 1.6.1, which fixed font rendering (issue #253)
* Add `.spacing(int)` method to add spacing (in dp) between document pages
* Fix drawing with `.onDraw(onDrawListener)`
* Add `.onDrawAll(onDrawListener)` method to draw on all pages
* Add small rendering improvements
* Fix rendering when duplicated pages are passed to `.pages(..)`
## 2.6.1 (2017-06-08)
* Fix disappearing scroll handle
## 2.6.0 (2017-06-04)
* Fix fling on single-page documents
* Greatly improve overall fling experience
## 2.5.1 (2017-04-08)
* Temporarily downgrade PdfiumAndroid until #253 will be fixed
## 2.5.0 (2017-03-23)
* Update PdfiumAndroid to 1.6.0, which is based on newest Pdfium from Android 7.1.1. It should fix many rendering and fonts problems
* Add method `pdfView.fitToWidth()`, which called in `OnRenderListener.onInitiallyRendered()` will fit document to width of the screen (inspired by [1stmetro](https://github.com/1stmetro))
* Add change from pull request by [isanwenyu](https://github.com/isanwenyu) to get rid of rare IllegalArgumentException while rendering
* Add `OnRenderListener`, that will be called once, right before document is drawn on the screen
* Add `Configurator.enableAntialiasing()` to improve rendering on low-res screen a little bit (as suggested by [majkimester](majkimester))
* Modify engine to not block UI when big documents are loaded
* Change `Constants` interface and inner interfaces to static public classes, to allow modifying core config values
## 2.4.0 (2016-12-30)
* Merge pull request by [hansinator85](https://github.com/hansinator85) which allows to enable/disable rendering during scale
* Make rendering during scale disabled by default (looks better)
* Merge pull request by [cesquivias](https://github.com/cesquivias) which replaces RenderingAsyncTask with Handler to simply code and work with testing frameworks
## 2.3.0 (2016-11-19)
* Add mechanism for providing documents from different sources - more info in README
* Update PdfiumAndroid to 1.5.0
* Thanks to document sources and PdfiumAndroid update, in-memory documents are supported
* Fix not working OnClickListener on PDFView
* **com.github.barteksc.exception.FileNotFoundException** is deprecated and all usages was removed.
All exceptions are delivered to old Configurator#onError() listener.
## 2.2.0 (2016-11-15)
* Merge pull request by [skarempudi](https://github.com/skarempudi) which fixes SDK 23 permission problems in sample app
* Merge pull request by skarempudi for showing info on phones without file manager
* Add feature from 1.x - canvas is set to drawable from View#getBackground()
## 2.1.0 (2016-09-16)
* fixed loading document from subfolder in assets directory
* fixed scroll handle NPE after document loading error (improvement of 2.0.3 fix)
* fixed incorrect scroll handle position with additional views in RelativeLayout
* improved cache usage and fixed bug with rendering when zooming
* if you are using custom scroll handle: scroll handle implementation changed a little bit, check DefaultScrollHandle source for details
## 2.0.3 (2016-08-30)
* Fix scroll handle NPE after document loading error
## 2.0.2 (2016-08-27)
* Fix exceptions caused by improperly finishing rendering task
## 2.0.1 (2016-08-16)
* Fix NPE when onDetachFromWindow is called
## 2.0.0 (2016-08-14)
* few API changes
* improved rendering speed and accuracy
* added continuous scroll - now it behaves like Adobe Reader and others
* added `fling` scroll gesture for velocity based scrolling
* added scroll handle as a replacement for scrollbar
### Changes in 2.0 API
* `Configurator#defaultPage(int)` and `PDFView#jumpTo(int)` now require page index (i.e. starting from 0)
* `OnPageChangeListener#onPageChanged(int, int)` is called with page index (i.e. starting from 0)
* removed scrollbar
* added scroll handle as a replacement for scrollbar, use with `Configurator#scrollHandle()`
* added `OnPageScrollListener` listener due to continuous scroll, register with `Configurator#onPageScroll()`
* default scroll direction is vertical, so `Configurator#swipeVertical()` was changed to `Configurator#swipeHorizontal()`
* removed minimap and mask configuration
## 1.4.0 (2016-07-25)
* Fix NPE and IndexOutOfBound bugs when rendering parts
* Merge pull request by [paulo-sato-daitan](https://github.com/paulo-sato-daitan) for disabling page change animation
* Merge pull request by [Miha-x64](https://github.com/Miha-x64) for drawing background if set on `PDFView`
## 1.3.0 (2016-07-13)
* update PdfiumAndroid to 1.4.0 with support for rendering annotations
* merge pull request by [usef](https://github.com/usef) for rendering annotations
## 1.2.0 (2016-07-11)
* update PdfiumAndroid to 1.3.1 with support for bookmarks, Table Of Contents and documents with password:
* added method `PDFView#getDocumentMeta()`, which returns document metadata
* added method `PDFView#getTableOfContents()`, which returns whole tree of bookmarks in PDF document
* added method `Configurator#password(String)`
* added horizontal mode to **ScrollBar** - use `ScrollBar#setHorizontal(true)` or `app:sb_horizontal="true"` in XML
* block interaction with `PDFView` when document is not loaded - prevent some exceptions
* fix `PDFView` exceptions in layout preview (edit mode)
## 1.1.2 (2016-06-27)
* update PdfiumAndroid to 1.1.0, which fixes displaying multiple `PDFView`s at the same time and few errors with loading PDF documents.
## 1.1.1 (2016-06-17)
* fixes bug with strange behavior when indices passed to `.pages()` don't start with `0`.
## 1.1.0 (2016-06-16)
* added method `pdfView.fromUri(Uri)` for opening files from content providers
* updated PdfiumAndroid to 1.0.3, which should fix bug with exception
* updated sample with demonstration of `fromUri()` method
* some minor fixes
## 1.0.0 (2016-06-06)
* Initial release
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
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.
================================================
FILE: README.md
================================================
# 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
__AndroidPdfViewer 1.x is available on [AndroidPdfViewerV1](https://github.com/barteksc/AndroidPdfViewerV1)
repo, where can be developed independently. Version 1.x uses different engine for drawing document on canvas,
so if you don't like 2.x version, try 1.x.__
Library for displaying PDF documents on Android, with `animations`, `gestures`, `zoom` and `double tap` support.
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.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
* **16 KB Page Size Support**: Updated for Google Play compatibility requirement (November 1st, 2025)
## Changes in 3.0 API
* Replaced `Contants.PRELOAD_COUNT` with `PRELOAD_OFFSET`
* Removed `PDFView#fitToWidth()` (variant without arguments)
* Removed `Configurator#invalidPageColor(int)` method as invalid pages are not rendered
* Removed page size parameters from `OnRenderListener#onInitiallyRendered(int)` method, as document may have different page sizes
* Removed `PDFView#setSwipeVertical()` method
## Installation
Add to _build.gradle_:
`implementation 'com.github.barteksc:android-pdf-viewer:3.2.0-beta.1'`
or if you want to use more stable version:
`implementation 'com.github.barteksc:android-pdf-viewer:2.8.2'`
Library is available in jcenter repository, probably it'll be in Maven Central soon.
## 16 KB Page Size Support ✅ FIXED
**✅ RESOLVED**: This library has been updated and **successfully fixed** to support 16 KB page sizes for Google Play compatibility. Starting November 1st, 2025, all new apps and updates targeting Android 15+ must support 16 KB page sizes.
### ✅ What Was Fixed:
- **Issue**: The `pdfium-android:1.9.0` dependency contained prebuilt native libraries that were not aligned for 16 KB page sizes
- **Solution**: Implemented compressed shared libraries configuration and post-build realignment scripts
- **Result**: APK now passes all 16 KB alignment checks and is Google Play compliant
### Key Updates Made:
- **AGP Version**: Using 8.13.0 (above required 8.5.1)
- **NDK Version**: Updated to r28+ for 16 KB support
- **Packaging**: Configured for compressed shared libraries to avoid alignment issues
- **Native Libraries**: All native libraries are properly aligned for 16 KB page sizes
- **Realignment Scripts**: Added automated tools to fix alignment issues
### ✅ Verification:
Use the provided scripts to verify 16 KB alignment:
- **Linux/macOS**: `./check_16kb_alignment.sh your-app.apk`
- **Windows**: `.\check_16kb_alignment.ps1 -ApkFile "your-app.apk"`
- **Fix Alignment**: `.\realign_apk.bat "your-app.apk"`
### 🎉 Google Play Compliance:
Your app will now **pass Google Play's 16 KB compatibility checks** and work on devices with 16 KB page sizes.
For more details, see [16KB_SUPPORT.md](16KB_SUPPORT.md).
## ProGuard
If you are using ProGuard, add following rule to proguard config file:
```proguard
-keep class com.shockwave.**
```
## Include PDFView in your layout
``` xml
<com.github.barteksc.pdfviewer.PDFView
android:id="@+id/pdfView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
```
## Load a PDF file
All available options with default values:
``` java
pdfView.fromUri(Uri)
or
pdfView.fromFile(File)
or
pdfView.fromBytes(byte[])
or
pdfView.fromStream(InputStream) // stream is written to bytearray - native code cannot use Java Streams
or
pdfView.fromSource(DocumentSource)
or
pdfView.fromAsset(String)
.pages(0, 2, 1, 3, 3, 3) // all pages are displayed by default
.enableSwipe(true) // allows to block changing pages using swipe
.swipeHorizontal(false)
.enableDoubletap(true)
.defaultPage(0)
// allows to draw something on the current page, usually visible in the middle of the screen
.onDraw(onDrawListener)
// allows to draw something on all pages, separately for every page. Called only for visible pages
.onDrawAll(onDrawListener)
.onLoad(onLoadCompleteListener) // called after document is loaded and starts to be rendered
.onPageChange(onPageChangeListener)
.onPageScroll(onPageScrollListener)
.onError(onErrorListener)
.onPageError(onPageErrorListener)
.onRender(onRenderListener) // called after document is rendered for the first time
// called on single tap, return true if handled, false to toggle scroll handle visibility
.onTap(onTapListener)
.onLongPress(onLongPressListener)
.enableAnnotationRendering(false) // render annotations (such as comments, colors or forms)
.password(null)
.scrollHandle(null)
.enableAntialiasing(true) // improve rendering a little bit on low-res screens
// spacing between pages in dp. To define spacing color, set view background
.spacing(0)
.autoSpacing(false) // add dynamic spacing to fit each page on its own on the screen
.linkHandler(DefaultLinkHandler)
.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();
```
* `pages` is optional, it allows you to filter and order the pages of the PDF as you need
## Scroll handle
Scroll handle is replacement for **ScrollBar** from 1.x branch.
From version 2.1.0 putting **PDFView** in **RelativeLayout** to use **ScrollHandle** is not required, you can use any layout.
To use scroll handle just register it using method `Configurator#scrollHandle()`.
This method accepts implementations of **ScrollHandle** interface.
There is default implementation shipped with AndroidPdfViewer, and you can use it with
`.scrollHandle(new DefaultScrollHandle(this))`.
**DefaultScrollHandle** is placed on the right (when scrolling vertically) or on the bottom (when scrolling horizontally).
By using constructor with second argument (`new DefaultScrollHandle(this, true)`), handle can be placed left or top.
You can also create custom scroll handles, just implement **ScrollHandle** interface.
All methods are documented as Javadoc comments on interface [source](https://github.com/barteksc/AndroidPdfViewer/tree/master/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/scroll/ScrollHandle.java).
## Document sources
Version 2.3.0 introduced _document sources_, which are just providers for PDF documents.
Every provider implements **DocumentSource** interface.
Predefined providers are available in **com.github.barteksc.pdfviewer.source** package and can be used as
samples for creating custom ones.
Predefined providers can be used with shorthand methods:
```
pdfView.fromUri(Uri)
pdfView.fromFile(File)
pdfView.fromBytes(byte[])
pdfView.fromStream(InputStream)
pdfView.fromAsset(String)
```
Custom providers may be used with `pdfView.fromSource(DocumentSource)` method.
## Links
Version 3.0.0 introduced support for links in PDF documents. By default, **DefaultLinkHandler**
is used and clicking on link that references page in same document causes jump to destination page
and clicking on link that targets some URI causes opening it in default application.
You can also create custom link handlers, just implement **LinkHandler** interface and set it using
`Configurator#linkHandler(LinkHandler)` method. Take a look at [DefaultLinkHandler](https://github.com/barteksc/AndroidPdfViewer/tree/master/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/link/DefaultLinkHandler.java)
source to implement custom behavior.
## Pages fit policy
Since version 3.0.0, library supports fitting pages into the screen in 3 modes:
* WIDTH - width of widest page is equal to screen width
* HEIGHT - height of highest page is equal to screen height
* BOTH - based on widest and highest pages, every page is scaled to be fully visible on screen
Apart from selected policy, every page is scaled to have size relative to other pages.
Fit policy can be set using `Configurator#pageFitPolicy(FitPolicy)`. Default policy is **WIDTH**.
## Additional options
### Bitmap quality
By default, generated bitmaps are _compressed_ with `RGB_565` format to reduce memory consumption.
Rendering with `ARGB_8888` can be forced by using `pdfView.useBestQuality(true)` method.
### Double tap zooming
There are three zoom levels: min (default 1), mid (default 1.75) and max (default 3). On first double tap,
view is zoomed to mid level, on second to max level, and on third returns to min level.
If you are between mid and max levels, double tapping causes zooming to max and so on.
Zoom levels can be changed using following methods:
``` java
void setMinZoom(float zoom);
void setMidZoom(float zoom);
void setMaxZoom(float zoom);
```
## Possible questions
### Why resulting apk is so big?
Android PdfViewer depends on PdfiumAndroid, which is set of native libraries (almost 16 MB) for many architectures.
Apk must contain all this libraries to run on every device available on market.
Fortunately, Google Play allows us to upload multiple apks, e.g. one per every architecture.
There is good article on automatically splitting your application into multiple apks,
available [here](http://ph0b.com/android-studio-gradle-and-ndk-integration/).
Most important section is _Improving multiple APKs creation and versionCode handling with APK Splits_, but whole article is worth reading.
You only need to do this in your application, no need for forking PdfiumAndroid or so.
### Why I cannot open PDF from URL?
Downloading files is long running process which must be aware of Activity lifecycle, must support some configuration,
data cleanup and caching, so creating such module will probably end up as new library.
### How can I show last opened page after configuration change?
You have to store current page number and then set it with `pdfView.defaultPage(page)`, refer to sample app
### How can I fit document to screen width (eg. on orientation change)?
Use `FitPolicy.WIDTH` policy or add following snippet when you want to fit desired page in document with different page sizes:
``` java
Configurator.onRender(new OnRenderListener() {
@Override
public void onInitiallyRendered(int pages, float pageWidth, float pageHeight) {
pdfView.fitToWidth(pageIndex);
}
});
```
### How can I scroll through single pages like a ViewPager?
You can use a combination of the following settings to get scroll and fling behaviour similar to a ViewPager:
``` java
.swipeHorizontal(true)
.pageSnap(true)
.autoSpacing(true)
.pageFling(true)
```
## One more thing
If you have any suggestions on making this lib better, write me, create issue or write some code and send pull request.
## License
Created with the help of android-pdfview by [Joan Zapata](http://joanzapata.com/)
```
Copyright 2017 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.
```
================================================
FILE: android-pdf-viewer/bintray.gradle
================================================
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
}
}
}
================================================
FILE: android-pdf-viewer/build.gradle
================================================
apply plugin: 'com.android.library'
ext {
bintrayRepo = 'maven'
bintrayName = 'android-pdf-viewer'
publishedGroupId = 'com.github.barteksc'
libraryName = 'AndroidPdfViewer'
artifact = 'android-pdf-viewer'
libraryDescription = 'Android view for displaying PDFs rendered with PdfiumAndroid'
siteUrl = 'https://github.com/barteksc/AndroidPdfViewer'
gitUrl = 'https://github.com/barteksc/AndroidPdfViewer.git'
libraryVersion = '3.2.0-beta.1'
developerId = 'barteksc'
developerName = 'Bartosz Schiller'
developerEmail = 'barteksch@boo.pl'
licenseName = 'The Apache Software License, Version 2.0'
licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
allLicenses = ["Apache-2.0"]
}
android {
namespace 'com.github.barteksc.pdfviewer'
compileSdkVersion 36
defaultConfig {
minSdkVersion 21
targetSdkVersion 36
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
// Configure packaging for 16 KB page size compatibility.
// Native libraries should be stored uncompressed and page-aligned in the APK.
packagingOptions {
jniLibs {
// Setting to false ensures native libraries are stored uncompressed and aligned.
// This is the default for AGP 3.6+ but explicitly set for clarity.
useLegacyPackaging false
}
}
// Enable 16 KB page size support for native libraries
ndkVersion "28.0.12433566" // Use NDK r28+ for 16 KB support
// Disable lint for now to focus on 16 KB compatibility
lint {
abortOnError false
}
}
dependencies {
implementation 'androidx.core:core:1.17.0'
api 'io.github.oothp:pdfium-android:1.9.5-beta01'
}
================================================
FILE: android-pdf-viewer/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/AnimationManager.java
================================================
/**
* Copyright 2016 Bartosz Schiller
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.graphics.PointF;
import android.view.animation.DecelerateInterpolator;
import android.widget.OverScroller;
/**
* This manager is used by the PDFView to launch animations.
* It uses the ValueAnimator appeared in API 11 to start
* an animation, and call moveTo() on the PDFView as a result
* of each animation update.
*/
class AnimationManager {
private PDFView pdfView;
private ValueAnimator animation;
private OverScroller scroller;
private boolean flinging = false;
private boolean pageFlinging = false;
public AnimationManager(PDFView pdfView) {
this.pdfView = pdfView;
scroller = new OverScroller(pdfView.getContext());
}
public void startXAnimation(float xFrom, float xTo) {
stopAll();
animation = ValueAnimator.ofFloat(xFrom, xTo);
XAnimation xAnimation = new XAnimation();
animation.setInterpolator(new DecelerateInterpolator());
animation.addUpdateListener(xAnimation);
animation.addListener(xAnimation);
animation.setDuration(400);
animation.start();
}
public void startYAnimation(float yFrom, float yTo) {
stopAll();
animation = ValueAnimator.ofFloat(yFrom, yTo);
YAnimation yAnimation = new YAnimation();
animation.setInterpolator(new DecelerateInterpolator());
animation.addUpdateListener(yAnimation);
animation.addListener(yAnimation);
animation.setDuration(400);
animation.start();
}
public void startZoomAnimation(float centerX, float centerY, float zoomFrom, float zoomTo) {
stopAll();
animation = ValueAnimator.ofFloat(zoomFrom, zoomTo);
animation.setInterpolator(new DecelerateInterpolator());
ZoomAnimation zoomAnim = new ZoomAnimation(centerX, centerY);
animation.addUpdateListener(zoomAnim);
animation.addListener(zoomAnim);
animation.setDuration(400);
animation.start();
}
public void startFlingAnimation(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY) {
stopAll();
flinging = true;
scroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY);
}
public void startPageFlingAnimation(float targetOffset) {
if (pdfView.isSwipeVertical()) {
startYAnimation(pdfView.getCurrentYOffset(), targetOffset);
} else {
startXAnimation(pdfView.getCurrentXOffset(), targetOffset);
}
pageFlinging = true;
}
void computeFling() {
if (scroller.computeScrollOffset()) {
pdfView.moveTo(scroller.getCurrX(), scroller.getCurrY());
pdfView.loadPageByOffset();
} else if (flinging) { // fling finished
flinging = false;
pdfView.loadPages();
hideHandle();
pdfView.performPageSnap();
}
}
public void stopAll() {
if (animation != null) {
animation.cancel();
animation = null;
}
stopFling();
}
public void stopFling() {
flinging = false;
scroller.forceFinished(true);
}
public boolean isFlinging() {
return flinging || pageFlinging;
}
class XAnimation extends AnimatorListenerAdapter implements AnimatorUpdateListener {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float offset = (Float) animation.getAnimatedValue();
pdfView.moveTo(offset, pdfView.getCurrentYOffset());
pdfView.loadPageByOffset();
}
@Override
public void onAnimationCancel(Animator animation) {
pdfView.loadPages();
pageFlinging = false;
hideHandle();
}
@Override
public void onAnimationEnd(Animator animation) {
pdfView.loadPages();
pageFlinging = false;
hideHandle();
}
}
class YAnimation extends AnimatorListenerAdapter implements AnimatorUpdateListener {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float offset = (Float) animation.getAnimatedValue();
pdfView.moveTo(pdfView.getCurrentXOffset(), offset);
pdfView.loadPageByOffset();
}
@Override
public void onAnimationCancel(Animator animation) {
pdfView.loadPages();
pageFlinging = false;
hideHandle();
}
@Override
public void onAnimationEnd(Animator animation) {
pdfView.loadPages();
pageFlinging = false;
hideHandle();
}
}
class ZoomAnimation implements AnimatorUpdateListener, AnimatorListener {
private final float centerX;
private final float centerY;
public ZoomAnimation(float centerX, float centerY) {
this.centerX = centerX;
this.centerY = centerY;
}
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float zoom = (Float) animation.getAnimatedValue();
pdfView.zoomCenteredTo(zoom, new PointF(centerX, centerY));
}
@Override
public void onAnimationCancel(Animator animation) {
pdfView.loadPages();
hideHandle();
}
@Override
public void onAnimationEnd(Animator animation) {
pdfView.loadPages();
pdfView.performPageSnap();
hideHandle();
}
@Override
public void onAnimationRepeat(Animator animation) {
}
@Override
public void onAnimationStart(Animator animation) {
}
}
private void hideHandle() {
if (pdfView.getScrollHandle() != null) {
pdfView.getScrollHandle().hideDelayed();
}
}
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/CacheManager.java
================================================
/**
* Copyright 2016 Bartosz Schiller
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.graphics.RectF;
import androidx.annotation.Nullable;
import com.github.barteksc.pdfviewer.model.PagePart;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.PriorityQueue;
import static com.github.barteksc.pdfviewer.util.Constants.Cache.CACHE_SIZE;
import static com.github.barteksc.pdfviewer.util.Constants.Cache.THUMBNAILS_CACHE_SIZE;
class CacheManager {
private final PriorityQueue<PagePart> passiveCache;
private final PriorityQueue<PagePart> activeCache;
private final List<PagePart> thumbnails;
private final Object passiveActiveLock = new Object();
private final PagePartComparator orderComparator = new PagePartComparator();
public CacheManager() {
activeCache = new PriorityQueue<>(CACHE_SIZE, orderComparator);
passiveCache = new PriorityQueue<>(CACHE_SIZE, orderComparator);
thumbnails = new ArrayList<>();
}
public void cachePart(PagePart part) {
synchronized (passiveActiveLock) {
// If cache too big, remove and recycle
makeAFreeSpace();
// Then add part
activeCache.offer(part);
}
}
public void makeANewSet() {
synchronized (passiveActiveLock) {
passiveCache.addAll(activeCache);
activeCache.clear();
}
}
private void makeAFreeSpace() {
synchronized (passiveActiveLock) {
while ((activeCache.size() + passiveCache.size()) >= CACHE_SIZE &&
!passiveCache.isEmpty()) {
PagePart part = passiveCache.poll();
part.getRenderedBitmap().recycle();
}
while ((activeCache.size() + passiveCache.size()) >= CACHE_SIZE &&
!activeCache.isEmpty()) {
activeCache.poll().getRenderedBitmap().recycle();
}
}
}
public void cacheThumbnail(PagePart part) {
synchronized (thumbnails) {
// If cache too big, remove and recycle
while (thumbnails.size() >= THUMBNAILS_CACHE_SIZE) {
thumbnails.remove(0).getRenderedBitmap().recycle();
}
// Then add thumbnail
addWithoutDuplicates(thumbnails, part);
}
}
public boolean upPartIfContained(int page, RectF pageRelativeBounds, int toOrder) {
PagePart fakePart = new PagePart(page, null, pageRelativeBounds, false, 0);
PagePart found;
synchronized (passiveActiveLock) {
if ((found = find(passiveCache, fakePart)) != null) {
passiveCache.remove(found);
found.setCacheOrder(toOrder);
activeCache.offer(found);
return true;
}
return find(activeCache, fakePart) != null;
}
}
/**
* Return true if already contains the described PagePart
*/
public boolean containsThumbnail(int page, RectF pageRelativeBounds) {
PagePart fakePart = new PagePart(page, null, pageRelativeBounds, true, 0);
synchronized (thumbnails) {
for (PagePart part : thumbnails) {
if (part.equals(fakePart)) {
return true;
}
}
return false;
}
}
/**
* Add part if it doesn't exist, recycle bitmap otherwise
*/
private void addWithoutDuplicates(Collection<PagePart> collection, PagePart newPart) {
for (PagePart part : collection) {
if (part.equals(newPart)) {
newPart.getRenderedBitmap().recycle();
return;
}
}
collection.add(newPart);
}
@Nullable
private static PagePart find(PriorityQueue<PagePart> vector, PagePart fakePart) {
for (PagePart part : vector) {
if (part.equals(fakePart)) {
return part;
}
}
return null;
}
public List<PagePart> getPageParts() {
synchronized (passiveActiveLock) {
List<PagePart> parts = new ArrayList<>(passiveCache);
parts.addAll(activeCache);
return parts;
}
}
public List<PagePart> getThumbnails() {
synchronized (thumbnails) {
return thumbnails;
}
}
public void recycle() {
synchronized (passiveActiveLock) {
for (PagePart part : passiveCache) {
part.getRenderedBitmap().recycle();
}
passiveCache.clear();
for (PagePart part : activeCache) {
part.getRenderedBitmap().recycle();
}
activeCache.clear();
}
synchronized (thumbnails) {
for (PagePart part : thumbnails) {
part.getRenderedBitmap().recycle();
}
thumbnails.clear();
}
}
class PagePartComparator implements Comparator<PagePart> {
@Override
public int compare(PagePart part1, PagePart part2) {
if (part1.getCacheOrder() == part2.getCacheOrder()) {
return 0;
}
return part1.getCacheOrder() > part2.getCacheOrder() ? 1 : -1;
}
}
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/DecodingAsyncTask.java
================================================
/**
* Copyright 2016 Bartosz Schiller
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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<Void, Void, Throwable> {
private boolean cancelled;
private WeakReference<PDFView> 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;
}
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/DragPinchManager.java
================================================
/**
* Copyright 2016 Bartosz Schiller
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.graphics.PointF;
import android.graphics.RectF;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import com.github.barteksc.pdfviewer.model.LinkTapEvent;
import com.github.barteksc.pdfviewer.scroll.ScrollHandle;
import com.github.barteksc.pdfviewer.util.SnapEdge;
import com.shockwave.pdfium.PdfDocument;
import com.shockwave.pdfium.util.SizeF;
import static com.github.barteksc.pdfviewer.util.Constants.Pinch.MAXIMUM_ZOOM;
import static com.github.barteksc.pdfviewer.util.Constants.Pinch.MINIMUM_ZOOM;
/**
* This Manager takes care of moving the PDFView,
* set its zoom track user actions.
*/
class DragPinchManager implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener, ScaleGestureDetector.OnScaleGestureListener, View.OnTouchListener {
private PDFView pdfView;
private AnimationManager animationManager;
private GestureDetector gestureDetector;
private ScaleGestureDetector scaleGestureDetector;
private boolean scrolling = false;
private boolean scaling = false;
private boolean enabled = false;
DragPinchManager(PDFView pdfView, AnimationManager animationManager) {
this.pdfView = pdfView;
this.animationManager = animationManager;
gestureDetector = new GestureDetector(pdfView.getContext(), this);
scaleGestureDetector = new ScaleGestureDetector(pdfView.getContext(), this);
pdfView.setOnTouchListener(this);
}
void enable() {
enabled = true;
}
void disable() {
enabled = false;
}
void disableLongpress(){
gestureDetector.setIsLongpressEnabled(false);
}
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
boolean onTapHandled = pdfView.callbacks.callOnTap(e);
boolean linkTapped = checkLinkTapped(e.getX(), e.getY());
if (!onTapHandled && !linkTapped) {
ScrollHandle ps = pdfView.getScrollHandle();
if (ps != null && !pdfView.documentFitsView()) {
if (!ps.shown()) {
ps.show();
} else {
ps.hide();
}
}
}
pdfView.performClick();
return true;
}
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());
SizeF pageSize = pdfFile.getScaledPageSize(page, pdfView.getZoom());
int pageX, pageY;
if (pdfView.isSwipeVertical()) {
pageX = (int) pdfFile.getSecondaryPageOffset(page, pdfView.getZoom());
pageY = (int) pdfFile.getPageOffset(page, pdfView.getZoom());
} else {
pageY = (int) pdfFile.getSecondaryPageOffset(page, pdfView.getZoom());
pageX = (int) pdfFile.getPageOffset(page, pdfView.getZoom());
}
for (PdfDocument.Link link : pdfFile.getPageLinks(page)) {
RectF mapped = pdfFile.mapRectToDevice(page, pageX, pageY, (int) pageSize.getWidth(),
(int) pageSize.getHeight(), link.getBounds());
mapped.sort();
if (mapped.contains(mappedX, mappedY)) {
pdfView.callbacks.callLinkHandler(new LinkTapEvent(x, y, mappedX, mappedY, mapped, link));
return true;
}
}
return false;
}
private void startPageFling(MotionEvent downEvent, MotionEvent ev, float velocityX, float velocityY) {
if (!checkDoPageFling(velocityX, velocityY)) {
return;
}
int direction;
if (pdfView.isSwipeVertical()) {
direction = velocityY > 0 ? -1 : 1;
} else {
direction = velocityX > 0 ? -1 : 1;
}
// get the focused page during the down event to ensure only a single page is changed
float delta = pdfView.isSwipeVertical() ? ev.getY() - downEvent.getY() : ev.getX() - downEvent.getX();
float offsetX = pdfView.getCurrentXOffset() - delta * pdfView.getZoom();
float offsetY = pdfView.getCurrentYOffset() - delta * pdfView.getZoom();
int startingPage = pdfView.findFocusPage(offsetX, offsetY);
int targetPage = Math.max(0, Math.min(pdfView.getPageCount() - 1, startingPage + direction));
SnapEdge edge = pdfView.findSnapEdge(targetPage);
float offset = pdfView.snapOffsetForPage(targetPage, edge);
animationManager.startPageFlingAnimation(-offset);
}
@Override
public boolean onDoubleTap(MotionEvent e) {
if (!pdfView.isDoubletapEnabled()) {
return false;
}
if (pdfView.getZoom() < pdfView.getMidZoom()) {
pdfView.zoomWithAnimation(e.getX(), e.getY(), pdfView.getMidZoom());
} else if (pdfView.getZoom() < pdfView.getMaxZoom()) {
pdfView.zoomWithAnimation(e.getX(), e.getY(), pdfView.getMaxZoom());
} else {
pdfView.resetZoomWithAnimation();
}
return true;
}
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
return false;
}
@Override
public boolean onDown(MotionEvent e) {
animationManager.stopFling();
return true;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
scrolling = true;
if (pdfView.isZooming() || pdfView.isSwipeEnabled()) {
pdfView.moveRelativeTo(-distanceX, -distanceY);
}
if (!scaling || pdfView.doRenderDuringScale()) {
pdfView.loadPageByOffset();
}
return true;
}
private void onScrollEnd(MotionEvent event) {
pdfView.loadPages();
hideHandle();
if (!animationManager.isFlinging()) {
pdfView.performPageSnap();
}
}
@Override
public void onLongPress(MotionEvent e) {
pdfView.callbacks.callOnLongPress(e);
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if (!pdfView.isSwipeEnabled()) {
return false;
}
if (pdfView.isPageFlingEnabled()) {
if (pdfView.pageFillsScreen()) {
onBoundedFling(velocityX, velocityY);
} else {
startPageFling(e1, e2, velocityX, velocityY);
}
return true;
}
int xOffset = (int) pdfView.getCurrentXOffset();
int yOffset = (int) pdfView.getCurrentYOffset();
float minX, minY;
PdfFile pdfFile = pdfView.pdfFile;
if (pdfView.isSwipeVertical()) {
minX = -(pdfView.toCurrentScale(pdfFile.getMaxPageWidth()) - pdfView.getWidth());
minY = -(pdfFile.getDocLen(pdfView.getZoom()) - pdfView.getHeight());
} else {
minX = -(pdfFile.getDocLen(pdfView.getZoom()) - pdfView.getWidth());
minY = -(pdfView.toCurrentScale(pdfFile.getMaxPageHeight()) - pdfView.getHeight());
}
animationManager.startFlingAnimation(xOffset, yOffset, (int) (velocityX), (int) (velocityY),
(int) minX, 0, (int) minY, 0);
return true;
}
private void onBoundedFling(float velocityX, float velocityY) {
int xOffset = (int) pdfView.getCurrentXOffset();
int yOffset = (int) pdfView.getCurrentYOffset();
PdfFile pdfFile = pdfView.pdfFile;
float pageStart = -pdfFile.getPageOffset(pdfView.getCurrentPage(), pdfView.getZoom());
float pageEnd = pageStart - pdfFile.getPageLength(pdfView.getCurrentPage(), pdfView.getZoom());
float minX, minY, maxX, maxY;
if (pdfView.isSwipeVertical()) {
minX = -(pdfView.toCurrentScale(pdfFile.getMaxPageWidth()) - pdfView.getWidth());
minY = pageEnd + pdfView.getHeight();
maxX = 0;
maxY = pageStart;
} else {
minX = pageEnd + pdfView.getWidth();
minY = -(pdfView.toCurrentScale(pdfFile.getMaxPageHeight()) - pdfView.getHeight());
maxX = pageStart;
maxY = 0;
}
animationManager.startFlingAnimation(xOffset, yOffset, (int) (velocityX), (int) (velocityY),
(int) minX, (int) maxX, (int) minY, (int) maxY);
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
float dr = detector.getScaleFactor();
float wantedZoom = pdfView.getZoom() * dr;
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;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
scaling = true;
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
pdfView.loadPages();
hideHandle();
scaling = false;
}
@Override
public boolean onTouch(View v, MotionEvent event) {
if (!enabled) {
return false;
}
boolean retVal = scaleGestureDetector.onTouchEvent(event);
retVal = gestureDetector.onTouchEvent(event) || retVal;
if (event.getAction() == MotionEvent.ACTION_UP) {
if (scrolling) {
scrolling = false;
onScrollEnd(event);
}
}
return retVal;
}
private void hideHandle() {
ScrollHandle scrollHandle = pdfView.getScrollHandle();
if (scrollHandle != null && scrollHandle.shown()) {
scrollHandle.hideDelayed();
}
}
private boolean checkDoPageFling(float velocityX, float velocityY) {
float absX = Math.abs(velocityX);
float absY = Math.abs(velocityY);
return pdfView.isSwipeVertical() ? absY > absX : absX > absY;
}
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/PDFView.java
================================================
/**
* Copyright 2016 Bartosz Schiller
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
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;
import android.widget.RelativeLayout;
import com.github.barteksc.pdfviewer.exception.PageRenderingException;
import com.github.barteksc.pdfviewer.link.DefaultLinkHandler;
import com.github.barteksc.pdfviewer.link.LinkHandler;
import com.github.barteksc.pdfviewer.listener.Callbacks;
import com.github.barteksc.pdfviewer.listener.OnDrawListener;
import com.github.barteksc.pdfviewer.listener.OnErrorListener;
import com.github.barteksc.pdfviewer.listener.OnLoadCompleteListener;
import com.github.barteksc.pdfviewer.listener.OnLongPressListener;
import com.github.barteksc.pdfviewer.listener.OnPageChangeListener;
import com.github.barteksc.pdfviewer.listener.OnPageErrorListener;
import com.github.barteksc.pdfviewer.listener.OnPageScrollListener;
import com.github.barteksc.pdfviewer.listener.OnRenderListener;
import com.github.barteksc.pdfviewer.listener.OnTapListener;
import com.github.barteksc.pdfviewer.model.PagePart;
import com.github.barteksc.pdfviewer.scroll.ScrollHandle;
import com.github.barteksc.pdfviewer.source.AssetSource;
import com.github.barteksc.pdfviewer.source.ByteArraySource;
import com.github.barteksc.pdfviewer.source.DocumentSource;
import com.github.barteksc.pdfviewer.source.FileSource;
import com.github.barteksc.pdfviewer.source.InputStreamSource;
import com.github.barteksc.pdfviewer.source.UriSource;
import com.github.barteksc.pdfviewer.util.Constants;
import com.github.barteksc.pdfviewer.util.FitPolicy;
import com.github.barteksc.pdfviewer.util.MathUtils;
import com.github.barteksc.pdfviewer.util.SnapEdge;
import com.github.barteksc.pdfviewer.util.Util;
import com.shockwave.pdfium.PdfDocument;
import com.shockwave.pdfium.PdfiumCore;
import com.shockwave.pdfium.util.Size;
import com.shockwave.pdfium.util.SizeF;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* It supports animations, zoom, cache, and swipe.
* <p>
* To fully understand this class you must know its principles :
* - The PDF document is seen as if we always want to draw all the pages.
* - The thing is that we only draw the visible parts.
* - All parts are the same size, this is because we can't interrupt a native page rendering,
* so we need these renderings to be as fast as possible, and be able to interrupt them
* as soon as we can.
* - The parts are loaded when the current offset or the current zoom level changes
* <p>
* Important :
* - DocumentPage = A page of the PDF document.
* - UserPage = A page as defined by the user.
* By default, they're the same. But the user can change the pages order
* using {@link #load(DocumentSource, String, int[])}. In this
* particular case, a userPage of 5 can refer to a documentPage of 17.
*/
public class PDFView extends RelativeLayout {
private static final String TAG = PDFView.class.getSimpleName();
public static final float DEFAULT_MAX_SCALE = 3.0f;
public static final float DEFAULT_MID_SCALE = 1.75f;
public static final float DEFAULT_MIN_SCALE = 1.0f;
private float minZoom = DEFAULT_MIN_SCALE;
private float midZoom = DEFAULT_MID_SCALE;
private float maxZoom = DEFAULT_MAX_SCALE;
/**
* START - scrolling in first page direction
* END - scrolling in last page direction
* NONE - not scrolling
*/
enum ScrollDir {
NONE, START, END
}
private ScrollDir scrollDir = ScrollDir.NONE;
/** Rendered parts go to the cache manager */
CacheManager cacheManager;
/** Animation manager manage all offset and zoom animation */
private AnimationManager animationManager;
/** Drag manager manage all touch events */
private DragPinchManager dragPinchManager;
PdfFile pdfFile;
/** The index of the current sequence */
private int currentPage;
/**
* If you picture all the pages side by side in their optimal width,
* and taking into account the zoom level, the current offset is the
* position of the left border of the screen in this big picture
*/
private float currentXOffset = 0;
/**
* If you picture all the pages side by side in their optimal width,
* and taking into account the zoom level, the current offset is the
* position of the left border of the screen in this big picture
*/
private float currentYOffset = 0;
/** The zoom level, always >= 1 */
private float zoom = 1f;
/** True if the PDFView has been recycled */
private boolean recycled = true;
/** Current state of the view */
private State state = State.DEFAULT;
/** Async task used during the loading phase to decode a PDF document */
private DecodingAsyncTask decodingAsyncTask;
/** The thread {@link #renderingHandler} will run on */
private HandlerThread renderingHandlerThread;
/** Handler always waiting in the background and rendering tasks */
RenderingHandler renderingHandler;
private PagesLoader pagesLoader;
Callbacks callbacks = new Callbacks();
/** Paint object for drawing */
private Paint paint;
/** Paint object for drawing debug stuff */
private Paint debugPaint;
/** 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 */
private boolean swipeVertical = true;
private boolean enableSwipe = true;
private boolean doubletapEnabled = true;
private boolean nightMode = false;
private boolean pageSnap = true;
/** Pdfium core for loading and rendering PDFs */
private PdfiumCore pdfiumCore;
private ScrollHandle scrollHandle;
private boolean isScrollHandleInit = false;
ScrollHandle getScrollHandle() {
return scrollHandle;
}
/**
* True if bitmap should use ARGB_8888 format and take more memory
* False if bitmap should be compressed by using RGB_565 format and take less memory
*/
private boolean bestQuality = false;
/**
* True if annotations should be rendered
* False otherwise
*/
private boolean annotationRendering = false;
/**
* True if the view should render during scaling<br/>
* Can not be forced on older API versions (< Build.VERSION_CODES.KITKAT) as the GestureDetector does
* not detect scrolling while scaling.<br/>
* False otherwise
*/
private boolean renderDuringScale = false;
/** Antialiasing and bitmap filtering */
private boolean enableAntialiasing = true;
private PaintFlagsDrawFilter antialiasFilter =
new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
/** Spacing between pages, in px */
private int spacingPx = 0;
/** Add dynamic spacing to fit each page separately on the screen. */
private boolean autoSpacing = false;
/** Fling a single page at a time */
private boolean pageFling = true;
/** Pages numbers used when calling onDrawAllListener */
private List<Integer> onDrawPagesNums = new ArrayList<>(10);
/** Holds info whether view has been added to layout and has width and height */
private boolean hasSize = false;
/** Holds last used Configurator that should be loaded when view has size */
private Configurator waitingDocumentConfigurator;
/** Construct the initial view */
public PDFView(Context context, AttributeSet set) {
super(context, set);
renderingHandlerThread = new HandlerThread("PDF renderer");
if (isInEditMode()) {
return;
}
cacheManager = new CacheManager();
animationManager = new AnimationManager(this);
dragPinchManager = new DragPinchManager(this, animationManager);
pagesLoader = new PagesLoader(this);
paint = new Paint();
debugPaint = new Paint();
debugPaint.setStyle(Style.STROKE);
pdfiumCore = new PdfiumCore(context);
setWillNotDraw(false);
}
private void load(DocumentSource docSource, String password) {
load(docSource, password, null);
}
private void load(DocumentSource docSource, String password, int[] userPages) {
if (!recycled) {
throw new IllegalStateException("Don't call load on a PDF View without recycling it first.");
}
recycled = false;
// Start decoding document
decodingAsyncTask = new DecodingAsyncTask(docSource, password, userPages, this, pdfiumCore);
decodingAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
/**
* Go to the given page.
*
* @param page Page index.
*/
public void jumpTo(int page, boolean withAnimation) {
if (pdfFile == null) {
return;
}
page = pdfFile.determineValidPageNumberFrom(page);
float offset = page == 0 ? 0 : -pdfFile.getPageOffset(page, zoom);
if (swipeVertical) {
if (withAnimation) {
animationManager.startYAnimation(currentYOffset, offset);
} else {
moveTo(currentXOffset, offset);
}
} else {
if (withAnimation) {
animationManager.startXAnimation(currentXOffset, offset);
} else {
moveTo(offset, currentYOffset);
}
}
showPage(page);
}
public void jumpTo(int page) {
jumpTo(page, false);
}
void showPage(int pageNb) {
if (recycled) {
return;
}
// Check the page number and makes the
// difference between UserPages and DocumentPages
pageNb = pdfFile.determineValidPageNumberFrom(pageNb);
currentPage = pageNb;
loadPages();
if (scrollHandle != null && !documentFitsView()) {
scrollHandle.setPageNum(currentPage + 1);
}
callbacks.callOnPageChange(currentPage, pdfFile.getPagesCount());
}
/**
* Get current position as ratio of document length to visible area.
* 0 means that document start is visible, 1 that document end is visible
*
* @return offset between 0 and 1
*/
public float getPositionOffset() {
float offset;
if (swipeVertical) {
offset = -currentYOffset / (pdfFile.getDocLen(zoom) - getHeight());
} else {
offset = -currentXOffset / (pdfFile.getDocLen(zoom) - getWidth());
}
return MathUtils.limit(offset, 0, 1);
}
/**
* @param progress must be between 0 and 1
* @param moveHandle whether to move scroll handle
* @see PDFView#getPositionOffset()
*/
public void setPositionOffset(float progress, boolean moveHandle) {
if (swipeVertical) {
moveTo(currentXOffset, (-pdfFile.getDocLen(zoom) + getHeight()) * progress, moveHandle);
} else {
moveTo((-pdfFile.getDocLen(zoom) + getWidth()) * progress, currentYOffset, moveHandle);
}
loadPageByOffset();
}
public void setPositionOffset(float progress) {
setPositionOffset(progress, true);
}
public void stopFling() {
animationManager.stopFling();
}
public int getPageCount() {
if (pdfFile == null) {
return 0;
}
return pdfFile.getPagesCount();
}
public void setSwipeEnabled(boolean enableSwipe) {
this.enableSwipe = enableSwipe;
}
public void setNightMode(boolean nightMode) {
this.nightMode = nightMode;
if (nightMode) {
ColorMatrix colorMatrixInverted =
new ColorMatrix(new float[]{
-1, 0, 0, 0, 255,
0, -1, 0, 0, 255,
0, 0, -1, 0, 255,
0, 0, 0, 1, 0});
ColorMatrixColorFilter filter = new ColorMatrixColorFilter(colorMatrixInverted);
paint.setColorFilter(filter);
} else {
paint.setColorFilter(null);
}
}
void enableDoubletap(boolean enableDoubletap) {
this.doubletapEnabled = enableDoubletap;
}
boolean isDoubletapEnabled() {
return doubletapEnabled;
}
void onPageError(PageRenderingException ex) {
if (!callbacks.callOnPageError(ex.getPage(), ex.getCause())) {
Log.e(TAG, "Cannot open page " + ex.getPage(), ex.getCause());
}
}
public void recycle() {
waitingDocumentConfigurator = null;
animationManager.stopAll();
dragPinchManager.disable();
// Stop tasks
if (renderingHandler != null) {
renderingHandler.stop();
renderingHandler.removeMessages(RenderingHandler.MSG_RENDER_TASK);
}
if (decodingAsyncTask != null) {
decodingAsyncTask.cancel(true);
}
// Clear caches
cacheManager.recycle();
if (scrollHandle != null && isScrollHandleInit) {
scrollHandle.destroyLayout();
}
if (pdfFile != null) {
pdfFile.dispose();
pdfFile = null;
}
renderingHandler = null;
scrollHandle = null;
isScrollHandleInit = false;
currentXOffset = currentYOffset = 0;
zoom = 1f;
recycled = true;
callbacks = new Callbacks();
state = State.DEFAULT;
}
public boolean isRecycled() {
return recycled;
}
/** Handle fling animation */
@Override
public void computeScroll() {
super.computeScroll();
if (isInEditMode()) {
return;
}
animationManager.computeFling();
}
@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();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
hasSize = true;
if (waitingDocumentConfigurator != null) {
waitingDocumentConfigurator.load();
}
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) {
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();
}
@Override
public boolean canScrollHorizontally(int direction) {
if (pdfFile == null) {
return true;
}
if (swipeVertical) {
if (direction < 0 && currentXOffset < 0) {
return true;
} else if (direction > 0 && currentXOffset + toCurrentScale(pdfFile.getMaxPageWidth()) > getWidth()) {
return true;
}
} else {
if (direction < 0 && currentXOffset < 0) {
return true;
} else if (direction > 0 && currentXOffset + pdfFile.getDocLen(zoom) > getWidth()) {
return true;
}
}
return false;
}
@Override
public boolean canScrollVertically(int direction) {
if (pdfFile == null) {
return true;
}
if (swipeVertical) {
if (direction < 0 && currentYOffset < 0) {
return true;
} else if (direction > 0 && currentYOffset + pdfFile.getDocLen(zoom) > getHeight()) {
return true;
}
} else {
if (direction < 0 && currentYOffset < 0) {
return true;
} else if (direction > 0 && currentYOffset + toCurrentScale(pdfFile.getMaxPageHeight()) > getHeight()) {
return true;
}
}
return false;
}
@Override
protected void onDraw(Canvas canvas) {
if (isInEditMode()) {
return;
}
// As I said in this class javadoc, we can think of this canvas as a huge
// strip on which we draw all the images. We actually only draw the rendered
// parts, of course, but we render them in the place they belong in this huge
// strip.
// That's where Canvas.translate(x, y) becomes very helpful.
// This is the situation :
// _______________________________________________
// | | |
// | the actual | The big strip |
// | canvas | |
// |_____________| |
// |_______________________________________________|
//
// If the rendered part is on the bottom right corner of the strip
// we can draw it but we won't see it because the canvas is not big enough.
// But if we call translate(-X, -Y) on the canvas just before drawing the object :
// _______________________________________________
// | _____________|
// | The big strip | |
// | | the actual |
// | | canvas |
// |_________________________________|_____________|
//
// The object will be on the canvas.
// This technique is massively used in this method, and allows
// abstraction of the screen position when rendering the parts.
// Draws background
if (enableAntialiasing) {
canvas.setDrawFilter(antialiasFilter);
}
Drawable bg = getBackground();
if (bg == null) {
canvas.drawColor(nightMode ? Color.BLACK : Color.WHITE);
} else {
bg.draw(canvas);
}
if (recycled) {
return;
}
if (state != State.SHOWN) {
return;
}
// Moves the canvas before drawing any element
float currentXOffset = this.currentXOffset;
float currentYOffset = this.currentYOffset;
canvas.translate(currentXOffset, currentYOffset);
// Draws thumbnails
for (PagePart part : cacheManager.getThumbnails()) {
drawPart(canvas, part);
}
// Draws parts
for (PagePart part : cacheManager.getPageParts()) {
drawPart(canvas, part);
if (callbacks.getOnDrawAll() != null
&& !onDrawPagesNums.contains(part.getPage())) {
onDrawPagesNums.add(part.getPage());
}
}
for (Integer page : onDrawPagesNums) {
drawWithListener(canvas, page, callbacks.getOnDrawAll());
}
onDrawPagesNums.clear();
drawWithListener(canvas, currentPage, callbacks.getOnDraw());
// Restores the canvas position
canvas.translate(-currentXOffset, -currentYOffset);
}
private void drawWithListener(Canvas canvas, int page, OnDrawListener listener) {
if (listener != null) {
float translateX, translateY;
if (swipeVertical) {
translateX = 0;
translateY = pdfFile.getPageOffset(page, zoom);
} else {
translateY = 0;
translateX = pdfFile.getPageOffset(page, zoom);
}
canvas.translate(translateX, translateY);
SizeF size = pdfFile.getPageSize(page);
listener.onLayerDrawn(canvas,
toCurrentScale(size.getWidth()),
toCurrentScale(size.getHeight()),
page);
canvas.translate(-translateX, -translateY);
}
}
/** Draw a given PagePart on the canvas */
private void drawPart(Canvas canvas, PagePart part) {
// Can seem strange, but avoid lot of calls
RectF pageRelativeBounds = part.getPageRelativeBounds();
Bitmap renderedBitmap = part.getRenderedBitmap();
if (renderedBitmap.isRecycled()) {
return;
}
// Move to the target page
float localTranslationX = 0;
float localTranslationY = 0;
SizeF size = pdfFile.getPageSize(part.getPage());
if (swipeVertical) {
localTranslationY = pdfFile.getPageOffset(part.getPage(), zoom);
float maxWidth = pdfFile.getMaxPageWidth();
localTranslationX = toCurrentScale(maxWidth - size.getWidth()) / 2;
} else {
localTranslationX = pdfFile.getPageOffset(part.getPage(), zoom);
float maxHeight = pdfFile.getMaxPageHeight();
localTranslationY = toCurrentScale(maxHeight - size.getHeight()) / 2;
}
canvas.translate(localTranslationX, localTranslationY);
Rect srcRect = new Rect(0, 0, renderedBitmap.getWidth(),
renderedBitmap.getHeight());
float offsetX = toCurrentScale(pageRelativeBounds.left * size.getWidth());
float offsetY = toCurrentScale(pageRelativeBounds.top * size.getHeight());
float width = toCurrentScale(pageRelativeBounds.width() * size.getWidth());
float height = toCurrentScale(pageRelativeBounds.height() * size.getHeight());
// If we use float values for this rectangle, there will be
// a possible gap between page parts, especially when
// the zoom level is high.
RectF dstRect = new RectF((int) offsetX, (int) offsetY,
(int) (offsetX + width),
(int) (offsetY + height));
// Check if bitmap is in the screen
float translationX = currentXOffset + localTranslationX;
float translationY = currentYOffset + localTranslationY;
if (translationX + dstRect.left >= getWidth() || translationX + dstRect.right <= 0 ||
translationY + dstRect.top >= getHeight() || translationY + dstRect.bottom <= 0) {
canvas.translate(-localTranslationX, -localTranslationY);
return;
}
canvas.drawBitmap(renderedBitmap, srcRect, dstRect, paint);
if (Constants.DEBUG_MODE) {
debugPaint.setColor(part.getPage() % 2 == 0 ? Color.RED : Color.BLUE);
canvas.drawRect(dstRect, debugPaint);
}
// Restore the canvas position
canvas.translate(-localTranslationX, -localTranslationY);
}
/**
* Load all the parts around the center of the screen,
* taking into account X and Y offsets, zoom level, and
* the current page displayed
*/
public void loadPages() {
if (pdfFile == null || renderingHandler == null) {
return;
}
// Cancel all current tasks
renderingHandler.removeMessages(RenderingHandler.MSG_RENDER_TASK);
cacheManager.makeANewSet();
pagesLoader.loadPages();
redraw();
}
/** Called when the PDF is loaded */
void loadComplete(PdfFile pdfFile) {
state = State.LOADED;
this.pdfFile = pdfFile;
if (!renderingHandlerThread.isAlive()) {
renderingHandlerThread.start();
}
renderingHandler = new RenderingHandler(renderingHandlerThread.getLooper(), this);
renderingHandler.start();
if (scrollHandle != null) {
scrollHandle.setupLayout(this);
isScrollHandleInit = true;
}
dragPinchManager.enable();
callbacks.callOnLoadComplete(pdfFile.getPagesCount());
jumpTo(defaultPage, false);
}
void loadError(Throwable t) {
state = State.ERROR;
// store reference, because callbacks will be cleared in recycle() method
OnErrorListener onErrorListener = callbacks.getOnError();
recycle();
invalidate();
if (onErrorListener != null) {
onErrorListener.onError(t);
} else {
Log.e("PDFView", "load pdf error", t);
}
}
void redraw() {
invalidate();
}
/**
* Called when a rendering task is over and
* a PagePart has been freshly created.
*
* @param part The created PagePart.
*/
public void onBitmapRendered(PagePart part) {
// when it is first rendered part
if (state == State.LOADED) {
state = State.SHOWN;
callbacks.callOnRender(pdfFile.getPagesCount());
}
if (part.isThumbnail()) {
cacheManager.cacheThumbnail(part);
} else {
cacheManager.cachePart(part);
}
redraw();
}
public void moveTo(float offsetX, float offsetY) {
moveTo(offsetX, offsetY, true);
}
/**
* Move to the given X and Y offsets, but check them ahead of time
* to be sure not to go outside the the big strip.
*
* @param offsetX The big strip X offset to use as the left border of the screen.
* @param offsetY The big strip Y offset to use as the right border of the screen.
* @param moveHandle whether to move scroll handle or not
*/
public void moveTo(float offsetX, float offsetY, boolean moveHandle) {
if (swipeVertical) {
// Check X offset
float scaledPageWidth = toCurrentScale(pdfFile.getMaxPageWidth());
if (scaledPageWidth < getWidth()) {
offsetX = getWidth() / 2 - scaledPageWidth / 2;
} else {
if (offsetX > 0) {
offsetX = 0;
} else if (offsetX + scaledPageWidth < getWidth()) {
offsetX = getWidth() - scaledPageWidth;
}
}
// Check Y offset
float contentHeight = pdfFile.getDocLen(zoom);
if (contentHeight < getHeight()) { // whole document height visible on screen
offsetY = (getHeight() - contentHeight) / 2;
} else {
if (offsetY > 0) { // top visible
offsetY = 0;
} else if (offsetY + contentHeight < getHeight()) { // bottom visible
offsetY = -contentHeight + getHeight();
}
}
if (offsetY < currentYOffset) {
scrollDir = ScrollDir.END;
} else if (offsetY > currentYOffset) {
scrollDir = ScrollDir.START;
} else {
scrollDir = ScrollDir.NONE;
}
} else {
// Check Y offset
float scaledPageHeight = toCurrentScale(pdfFile.getMaxPageHeight());
if (scaledPageHeight < getHeight()) {
offsetY = getHeight() / 2 - scaledPageHeight / 2;
} else {
if (offsetY > 0) {
offsetY = 0;
} else if (offsetY + scaledPageHeight < getHeight()) {
offsetY = getHeight() - scaledPageHeight;
}
}
// Check X offset
float contentWidth = pdfFile.getDocLen(zoom);
if (contentWidth < getWidth()) { // whole document width visible on screen
offsetX = (getWidth() - contentWidth) / 2;
} else {
if (offsetX > 0) { // left visible
offsetX = 0;
} else if (offsetX + contentWidth < getWidth()) { // right visible
offsetX = -contentWidth + getWidth();
}
}
if (offsetX < currentXOffset) {
scrollDir = ScrollDir.END;
} else if (offsetX > currentXOffset) {
scrollDir = ScrollDir.START;
} else {
scrollDir = ScrollDir.NONE;
}
}
currentXOffset = offsetX;
currentYOffset = offsetY;
float positionOffset = getPositionOffset();
if (moveHandle && scrollHandle != null && !documentFitsView()) {
scrollHandle.setScroll(positionOffset);
}
callbacks.callOnPageScroll(getCurrentPage(), positionOffset);
redraw();
}
void loadPageByOffset() {
if (0 == pdfFile.getPagesCount()) {
return;
}
float offset, screenCenter;
if (swipeVertical) {
offset = currentYOffset;
screenCenter = ((float) getHeight()) / 2;
} else {
offset = currentXOffset;
screenCenter = ((float) getWidth()) / 2;
}
int page = pdfFile.getPageAtOffset(-(offset - screenCenter), zoom);
if (page >= 0 && page <= pdfFile.getPagesCount() - 1 && page != getCurrentPage()) {
showPage(page);
} else {
loadPages();
}
}
/**
* Animate to the nearest snapping position for the current SnapPolicy
*/
public void performPageSnap() {
if (!pageSnap || pdfFile == null || pdfFile.getPagesCount() == 0) {
return;
}
int centerPage = findFocusPage(currentXOffset, currentYOffset);
SnapEdge edge = findSnapEdge(centerPage);
if (edge == SnapEdge.NONE) {
return;
}
float offset = snapOffsetForPage(centerPage, edge);
if (swipeVertical) {
animationManager.startYAnimation(currentYOffset, -offset);
} else {
animationManager.startXAnimation(currentXOffset, -offset);
}
}
/**
* Find the edge to snap to when showing the specified page
*/
SnapEdge findSnapEdge(int page) {
if (!pageSnap || page < 0) {
return SnapEdge.NONE;
}
float currentOffset = swipeVertical ? currentYOffset : currentXOffset;
float offset = -pdfFile.getPageOffset(page, zoom);
int length = swipeVertical ? getHeight() : getWidth();
float pageLength = pdfFile.getPageLength(page, zoom);
if (length >= pageLength) {
return SnapEdge.CENTER;
} else if (currentOffset >= offset) {
return SnapEdge.START;
} else if (offset - pageLength > currentOffset - length) {
return SnapEdge.END;
} else {
return SnapEdge.NONE;
}
}
/**
* Get the offset to move to in order to snap to the page
*/
float snapOffsetForPage(int pageIndex, SnapEdge edge) {
float offset = pdfFile.getPageOffset(pageIndex, zoom);
float length = swipeVertical ? getHeight() : getWidth();
float pageLength = pdfFile.getPageLength(pageIndex, zoom);
if (edge == SnapEdge.CENTER) {
offset = offset - length / 2f + pageLength / 2f;
} else if (edge == SnapEdge.END) {
offset = offset - length + pageLength;
}
return offset;
}
int findFocusPage(float xOffset, float yOffset) {
float currOffset = swipeVertical ? yOffset : xOffset;
float length = swipeVertical ? getHeight() : getWidth();
// make sure first and last page can be found
if (currOffset > -1) {
return 0;
} else if (currOffset < -pdfFile.getDocLen(zoom) + length + 1) {
return pdfFile.getPagesCount() - 1;
}
// else find page in center
float center = currOffset - length / 2f;
return pdfFile.getPageAtOffset(-center, zoom);
}
/**
* @return true if single page fills the entire screen in the scrolling direction
*/
public boolean pageFillsScreen() {
float start = -pdfFile.getPageOffset(currentPage, zoom);
float end = start - pdfFile.getPageLength(currentPage, zoom);
if (isSwipeVertical()) {
return start > currentYOffset && end < currentYOffset - getHeight();
} else {
return start > currentXOffset && end < currentXOffset - getWidth();
}
}
/**
* Move relatively to the current position.
*
* @param dx The X difference you want to apply.
* @param dy The Y difference you want to apply.
* @see #moveTo(float, float)
*/
public void moveRelativeTo(float dx, float dy) {
moveTo(currentXOffset + dx, currentYOffset + dy);
}
/**
* Change the zoom level
*/
public void zoomTo(float zoom) {
this.zoom = zoom;
}
/**
* Change the zoom level, relatively to a pivot point.
* It will call moveTo() to make sure the given point stays
* in the middle of the screen.
*
* @param zoom The zoom level.
* @param pivot The point on the screen that should stays.
*/
public void zoomCenteredTo(float zoom, PointF pivot) {
float dzoom = zoom / this.zoom;
zoomTo(zoom);
float baseX = currentXOffset * dzoom;
float baseY = currentYOffset * dzoom;
baseX += (pivot.x - pivot.x * dzoom);
baseY += (pivot.y - pivot.y * dzoom);
moveTo(baseX, baseY);
}
/**
* @see #zoomCenteredTo(float, PointF)
*/
public void zoomCenteredRelativeTo(float dzoom, PointF pivot) {
zoomCenteredTo(zoom * dzoom, pivot);
}
/**
* Checks if whole document can be displayed on screen, doesn't include zoom
*
* @return true if whole document can displayed at once, false otherwise
*/
public boolean documentFitsView() {
float len = pdfFile.getDocLen(1);
if (swipeVertical) {
return len < getHeight();
} else {
return len < getWidth();
}
}
public void fitToWidth(int page) {
if (state != State.SHOWN) {
Log.e(TAG, "Cannot fit, document not rendered yet");
return;
}
zoomTo(getWidth() / pdfFile.getPageSize(page).getWidth());
jumpTo(page);
}
public SizeF getPageSize(int pageIndex) {
if (pdfFile == null) {
return new SizeF(0, 0);
}
return pdfFile.getPageSize(pageIndex);
}
public int getCurrentPage() {
return currentPage;
}
public float getCurrentXOffset() {
return currentXOffset;
}
public float getCurrentYOffset() {
return currentYOffset;
}
public float toRealScale(float size) {
return size / zoom;
}
public float toCurrentScale(float size) {
return size * zoom;
}
public float getZoom() {
return zoom;
}
public boolean isZooming() {
return zoom != minZoom;
}
private void setDefaultPage(int defaultPage) {
this.defaultPage = defaultPage;
}
public void resetZoom() {
zoomTo(minZoom);
}
public void resetZoomWithAnimation() {
zoomWithAnimation(minZoom);
}
public void zoomWithAnimation(float centerX, float centerY, float scale) {
animationManager.startZoomAnimation(centerX, centerY, zoom, scale);
}
public void zoomWithAnimation(float scale) {
animationManager.startZoomAnimation(getWidth() / 2, getHeight() / 2, zoom, scale);
}
private void setScrollHandle(ScrollHandle scrollHandle) {
this.scrollHandle = scrollHandle;
}
/**
* Get page number at given offset
*
* @param positionOffset scroll offset between 0 and 1
* @return page number at given offset, starting from 0
*/
public int getPageAtPositionOffset(float positionOffset) {
return pdfFile.getPageAtOffset(pdfFile.getDocLen(zoom) * positionOffset, zoom);
}
public float getMinZoom() {
return minZoom;
}
public void setMinZoom(float minZoom) {
this.minZoom = minZoom;
}
public float getMidZoom() {
return midZoom;
}
public void setMidZoom(float midZoom) {
this.midZoom = midZoom;
}
public float getMaxZoom() {
return maxZoom;
}
public void setMaxZoom(float maxZoom) {
this.maxZoom = maxZoom;
}
public void useBestQuality(boolean bestQuality) {
this.bestQuality = bestQuality;
}
public boolean isBestQuality() {
return bestQuality;
}
public boolean isSwipeVertical() {
return swipeVertical;
}
public boolean isSwipeEnabled() {
return enableSwipe;
}
private void setSwipeVertical(boolean swipeVertical) {
this.swipeVertical = swipeVertical;
}
public void enableAnnotationRendering(boolean annotationRendering) {
this.annotationRendering = annotationRendering;
}
public boolean isAnnotationRendering() {
return annotationRendering;
}
public void enableRenderDuringScale(boolean renderDuringScale) {
this.renderDuringScale = renderDuringScale;
}
public boolean isAntialiasing() {
return enableAntialiasing;
}
public void enableAntialiasing(boolean enableAntialiasing) {
this.enableAntialiasing = enableAntialiasing;
}
public int getSpacingPx() {
return spacingPx;
}
public boolean isAutoSpacingEnabled() {
return autoSpacing;
}
public void setPageFling(boolean pageFling) {
this.pageFling = pageFling;
}
public boolean isPageFlingEnabled() {
return pageFling;
}
private void setSpacing(int spacingDp) {
this.spacingPx = Util.getDP(getContext(), spacingDp);
}
private void setAutoSpacing(boolean autoSpacing) {
this.autoSpacing = autoSpacing;
}
private void setPageFitPolicy(FitPolicy pageFitPolicy) {
this.pageFitPolicy = pageFitPolicy;
}
public FitPolicy getPageFitPolicy() {
return pageFitPolicy;
}
private void setFitEachPage(boolean fitEachPage) {
this.fitEachPage = fitEachPage;
}
public boolean isFitEachPage() {
return fitEachPage;
}
public boolean isPageSnap() {
return pageSnap;
}
public void setPageSnap(boolean pageSnap) {
this.pageSnap = pageSnap;
}
public boolean doRenderDuringScale() {
return renderDuringScale;
}
/** Returns null if document is not loaded */
public PdfDocument.Meta getDocumentMeta() {
if (pdfFile == null) {
return null;
}
return pdfFile.getMetaData();
}
/** Will be empty until document is loaded */
public List<PdfDocument.Bookmark> getTableOfContents() {
if (pdfFile == null) {
return Collections.emptyList();
}
return pdfFile.getBookmarks();
}
/** Will be empty until document is loaded */
public List<PdfDocument.Link> getLinks(int page) {
if (pdfFile == null) {
return Collections.emptyList();
}
return pdfFile.getPageLinks(page);
}
/** Use an asset file as the pdf source */
public Configurator fromAsset(String assetName) {
return new Configurator(new AssetSource(assetName));
}
/** Use a file as the pdf source */
public Configurator fromFile(File file) {
return new Configurator(new FileSource(file));
}
/** Use URI as the pdf source, for use with content providers */
public Configurator fromUri(Uri uri) {
return new Configurator(new UriSource(uri));
}
/** Use bytearray as the pdf source, documents is not saved */
public Configurator fromBytes(byte[] bytes) {
return new Configurator(new ByteArraySource(bytes));
}
/** Use stream as the pdf source. Stream will be written to bytearray, because native code does not support Java Streams */
public Configurator fromStream(InputStream stream) {
return new Configurator(new InputStreamSource(stream));
}
/** Use custom source as pdf source */
public Configurator fromSource(DocumentSource docSource) {
return new Configurator(docSource);
}
private enum State {DEFAULT, LOADED, SHOWN, ERROR}
public class Configurator {
private final DocumentSource documentSource;
private int[] pageNumbers = null;
private boolean enableSwipe = true;
private boolean enableDoubletap = true;
private OnDrawListener onDrawListener;
private OnDrawListener onDrawAllListener;
private OnLoadCompleteListener onLoadCompleteListener;
private OnErrorListener onErrorListener;
private OnPageChangeListener onPageChangeListener;
private OnPageScrollListener onPageScrollListener;
private OnRenderListener onRenderListener;
private OnTapListener onTapListener;
private OnLongPressListener onLongPressListener;
private OnPageErrorListener onPageErrorListener;
private LinkHandler linkHandler = new DefaultLinkHandler(PDFView.this);
private int defaultPage = 0;
private boolean swipeHorizontal = false;
private boolean annotationRendering = false;
private String password = null;
private ScrollHandle scrollHandle = null;
private boolean antialiasing = true;
private int spacing = 0;
private boolean autoSpacing = false;
private FitPolicy pageFitPolicy = FitPolicy.WIDTH;
private boolean fitEachPage = false;
private boolean pageFling = false;
private boolean pageSnap = false;
private boolean nightMode = false;
private Configurator(DocumentSource documentSource) {
this.documentSource = documentSource;
}
public Configurator pages(int... pageNumbers) {
this.pageNumbers = pageNumbers;
return this;
}
public Configurator enableSwipe(boolean enableSwipe) {
this.enableSwipe = enableSwipe;
return this;
}
public Configurator enableDoubletap(boolean enableDoubletap) {
this.enableDoubletap = enableDoubletap;
return this;
}
public Configurator enableAnnotationRendering(boolean annotationRendering) {
this.annotationRendering = annotationRendering;
return this;
}
public Configurator onDraw(OnDrawListener onDrawListener) {
this.onDrawListener = onDrawListener;
return this;
}
public Configurator onDrawAll(OnDrawListener onDrawAllListener) {
this.onDrawAllListener = onDrawAllListener;
return this;
}
public Configurator onLoad(OnLoadCompleteListener onLoadCompleteListener) {
this.onLoadCompleteListener = onLoadCompleteListener;
return this;
}
public Configurator onPageScroll(OnPageScrollListener onPageScrollListener) {
this.onPageScrollListener = onPageScrollListener;
return this;
}
public Configurator onError(OnErrorListener onErrorListener) {
this.onErrorListener = onErrorListener;
return this;
}
public Configurator onPageError(OnPageErrorListener onPageErrorListener) {
this.onPageErrorListener = onPageErrorListener;
return this;
}
public Configurator onPageChange(OnPageChangeListener onPageChangeListener) {
this.onPageChangeListener = onPageChangeListener;
return this;
}
public Configurator onRender(OnRenderListener onRenderListener) {
this.onRenderListener = onRenderListener;
return this;
}
public Configurator onTap(OnTapListener onTapListener) {
this.onTapListener = onTapListener;
return this;
}
public Configurator onLongPress(OnLongPressListener onLongPressListener) {
this.onLongPressListener = onLongPressListener;
return this;
}
public Configurator linkHandler(LinkHandler linkHandler) {
this.linkHandler = linkHandler;
return this;
}
public Configurator defaultPage(int defaultPage) {
this.defaultPage = defaultPage;
return this;
}
public Configurator swipeHorizontal(boolean swipeHorizontal) {
this.swipeHorizontal = swipeHorizontal;
return this;
}
public Configurator password(String password) {
this.password = password;
return this;
}
public Configurator scrollHandle(ScrollHandle scrollHandle) {
this.scrollHandle = scrollHandle;
return this;
}
public Configurator enableAntialiasing(boolean antialiasing) {
this.antialiasing = antialiasing;
return this;
}
public Configurator spacing(int spacing) {
this.spacing = spacing;
return this;
}
public Configurator autoSpacing(boolean autoSpacing) {
this.autoSpacing = autoSpacing;
return this;
}
public Configurator pageFitPolicy(FitPolicy pageFitPolicy) {
this.pageFitPolicy = pageFitPolicy;
return this;
}
public Configurator fitEachPage(boolean fitEachPage) {
this.fitEachPage = fitEachPage;
return this;
}
public Configurator pageSnap(boolean pageSnap) {
this.pageSnap = pageSnap;
return this;
}
public Configurator pageFling(boolean pageFling) {
this.pageFling = pageFling;
return this;
}
public Configurator nightMode(boolean nightMode) {
this.nightMode = nightMode;
return this;
}
public Configurator disableLongpress() {
PDFView.this.dragPinchManager.disableLongpress();
return this;
}
public void load() {
if (!hasSize) {
waitingDocumentConfigurator = this;
return;
}
PDFView.this.recycle();
PDFView.this.callbacks.setOnLoadComplete(onLoadCompleteListener);
PDFView.this.callbacks.setOnError(onErrorListener);
PDFView.this.callbacks.setOnDraw(onDrawListener);
PDFView.this.callbacks.setOnDrawAll(onDrawAllListener);
PDFView.this.callbacks.setOnPageChange(onPageChangeListener);
PDFView.this.callbacks.setOnPageScroll(onPageScrollListener);
PDFView.this.callbacks.setOnRender(onRenderListener);
PDFView.this.callbacks.setOnTap(onTapListener);
PDFView.this.callbacks.setOnLongPress(onLongPressListener);
PDFView.this.callbacks.setOnPageError(onPageErrorListener);
PDFView.this.callbacks.setLinkHandler(linkHandler);
PDFView.this.setSwipeEnabled(enableSwipe);
PDFView.this.setNightMode(nightMode);
PDFView.this.enableDoubletap(enableDoubletap);
PDFView.this.setDefaultPage(defaultPage);
PDFView.this.setSwipeVertical(!swipeHorizontal);
PDFView.this.enableAnnotationRendering(annotationRendering);
PDFView.this.setScrollHandle(scrollHandle);
PDFView.this.enableAntialiasing(antialiasing);
PDFView.this.setSpacing(spacing);
PDFView.this.setAutoSpacing(autoSpacing);
PDFView.this.setPageFitPolicy(pageFitPolicy);
PDFView.this.setFitEachPage(fitEachPage);
PDFView.this.setPageSnap(pageSnap);
PDFView.this.setPageFling(pageFling);
if (pageNumbers != null) {
PDFView.this.load(documentSource, password, pageNumbers);
} else {
PDFView.this.load(documentSource, password);
}
}
}
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/PagesLoader.java
================================================
/**
* Copyright 2017 Bartosz Schiller
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.graphics.RectF;
import com.github.barteksc.pdfviewer.util.Constants;
import com.github.barteksc.pdfviewer.util.MathUtils;
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;
class PagesLoader {
private PDFView pdfView;
private int cacheOrder;
private float xOffset;
private float yOffset;
private float pageRelativePartWidth;
private float pageRelativePartHeight;
private float partRenderWidth;
private float partRenderHeight;
private final RectF thumbnailRect = new RectF(0, 0, 1, 1);
private final int preloadOffset;
private class Holder {
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) {
this.pdfView = pdfView;
this.preloadOffset = Util.getDP(pdfView.getContext(), PRELOAD_OFFSET);
}
private void getPageColsRows(GridSize grid, int pageIndex) {
SizeF size = pdfView.pdfFile.getPageSize(pageIndex);
float ratioX = 1f / size.getWidth();
float ratioY = 1f / size.getHeight();
final float partHeight = (Constants.PART_SIZE * ratioY) / pdfView.getZoom();
final float partWidth = (Constants.PART_SIZE * ratioX) / pdfView.getZoom();
grid.rows = MathUtils.ceil(1f / partHeight);
grid.cols = MathUtils.ceil(1f / partWidth);
}
private void calculatePartSize(GridSize grid) {
pageRelativePartWidth = 1f / (float) grid.cols;
pageRelativePartHeight = 1f / (float) grid.rows;
partRenderWidth = Constants.PART_SIZE / pageRelativePartWidth;
partRenderHeight = Constants.PART_SIZE / pageRelativePartHeight;
}
/**
* calculate the render range of each page
*/
private List<RenderRange> 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<RenderRange> 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;
}
pageLastXOffset = fixedLastXOffset;
pageLastYOffset = fixedLastYOffset;
} 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);
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 {
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;
}
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;
List<RenderRange> rangeList = getRenderRangeList(firstXOffset, firstYOffset, lastXOffset, lastYOffset);
for (RenderRange range : rangeList) {
loadThumbnail(range.page);
}
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;
}
}
}
private int loadPage(int page, int firstRow, int lastRow, int firstCol, int lastCol,
int nbOfPartsLoadable) {
int loaded = 0;
for (int row = firstRow; row <= lastRow; row++) {
for (int col = firstCol; col <= lastCol; col++) {
if (loadCell(page, row, col, pageRelativePartWidth, pageRelativePartHeight)) {
loaded++;
}
if (loaded >= nbOfPartsLoadable) {
return loaded;
}
}
}
return loaded;
}
private boolean loadCell(int page, int row, int col, float pageRelativePartWidth, float pageRelativePartHeight) {
float relX = pageRelativePartWidth * col;
float relY = pageRelativePartHeight * row;
float relWidth = pageRelativePartWidth;
float relHeight = pageRelativePartHeight;
float renderWidth = partRenderWidth;
float renderHeight = partRenderHeight;
if (relX + relWidth > 1) {
relWidth = 1 - relX;
}
if (relY + relHeight > 1) {
relHeight = 1 - relY;
}
renderWidth *= relWidth;
renderHeight *= relHeight;
RectF pageRelativeBounds = new RectF(relX, relY, relX + relWidth, relY + relHeight);
if (renderWidth > 0 && renderHeight > 0) {
if (!pdfView.cacheManager.upPartIfContained(page, pageRelativeBounds, cacheOrder)) {
pdfView.renderingHandler.addRenderingTask(page, renderWidth, renderHeight,
pageRelativeBounds, false, cacheOrder, pdfView.isBestQuality(),
pdfView.isAnnotationRendering());
}
cacheOrder++;
return true;
}
return false;
}
private void loadThumbnail(int page) {
SizeF pageSize = pdfView.pdfFile.getPageSize(page);
float thumbnailWidth = pageSize.getWidth() * Constants.THUMBNAIL_RATIO;
float thumbnailHeight = pageSize.getHeight() * Constants.THUMBNAIL_RATIO;
if (!pdfView.cacheManager.containsThumbnail(page, thumbnailRect)) {
pdfView.renderingHandler.addRenderingTask(page,
thumbnailWidth, thumbnailHeight, thumbnailRect,
true, 0, pdfView.isBestQuality(), pdfView.isAnnotationRendering());
}
}
void loadPages() {
cacheOrder = 1;
xOffset = -MathUtils.max(pdfView.getCurrentXOffset(), 0);
yOffset = -MathUtils.max(pdfView.getCurrentYOffset(), 0);
loadVisible();
}
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/PdfFile.java
================================================
/**
* Copyright 2017 Bartosz Schiller
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.SparseBooleanArray;
import com.github.barteksc.pdfviewer.exception.PageRenderingException;
import com.github.barteksc.pdfviewer.util.FitPolicy;
import com.github.barteksc.pdfviewer.util.PageSizeCalculator;
import com.shockwave.pdfium.PdfDocument;
import com.shockwave.pdfium.PdfiumCore;
import com.shockwave.pdfium.util.Size;
import com.shockwave.pdfium.util.SizeF;
import java.util.ArrayList;
import java.util.List;
class PdfFile {
private static final Object lock = new Object();
private PdfDocument pdfDocument;
private PdfiumCore pdfiumCore;
private int pagesCount = 0;
/** Original page sizes */
private List<Size> originalPageSizes = new ArrayList<>();
/** Scaled page sizes */
private List<SizeF> pageSizes = new ArrayList<>();
/** Opened pages with indicator whether opening was successful */
private SparseBooleanArray openedPages = new SparseBooleanArray();
/** Page with maximum width */
private Size originalMaxWidthPageSize = new Size(0, 0);
/** Page with maximum height */
private Size originalMaxHeightPageSize = new Size(0, 0);
/** Scaled page with maximum height */
private SizeF maxHeightPageSize = new SizeF(0, 0);
/** Scaled page with maximum width */
private SizeF maxWidthPageSize = new SizeF(0, 0);
/** True if scrolling is vertical, else it's horizontal */
private boolean isVertical;
/** Fixed spacing between pages in pixels */
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 */
private List<Float> pageOffsets = new ArrayList<>();
/** Calculated auto spacing for pages */
private List<Float> pageSpacing = new ArrayList<>();
/** 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)
*/
private int[] originalUserPages;
PdfFile(PdfiumCore pdfiumCore, PdfDocument pdfDocument, FitPolicy pageFitPolicy, Size viewSize, int[] originalUserPages,
boolean isVertical, int spacing, boolean autoSpacing, boolean fitEachPage) {
this.pdfiumCore = pdfiumCore;
this.pdfDocument = pdfDocument;
this.pageFitPolicy = pageFitPolicy;
this.originalUserPages = originalUserPages;
this.isVertical = isVertical;
this.spacingPx = spacing;
this.autoSpacing = autoSpacing;
this.fitEachPage = fitEachPage;
setup(viewSize);
}
private void setup(Size viewSize) {
if (originalUserPages != null) {
pagesCount = originalUserPages.length;
} else {
pagesCount = pdfiumCore.getPageCount(pdfDocument);
}
for (int i = 0; i < pagesCount; i++) {
Size pageSize = pdfiumCore.getPageSize(pdfDocument, documentPage(i));
if (pageSize.getWidth() > originalMaxWidthPageSize.getWidth()) {
originalMaxWidthPageSize = pageSize;
}
if (pageSize.getHeight() > originalMaxHeightPageSize.getHeight()) {
originalMaxHeightPageSize = pageSize;
}
originalPageSizes.add(pageSize);
}
recalculatePageSizes(viewSize);
}
/**
* Call after view size change to recalculate page sizes, offsets and document length
*
* @param viewSize new size of changed view
*/
public void recalculatePageSizes(Size viewSize) {
pageSizes.clear();
PageSizeCalculator calculator = new PageSizeCalculator(pageFitPolicy, originalMaxWidthPageSize,
originalMaxHeightPageSize, viewSize, fitEachPage);
maxWidthPageSize = calculator.getOptimalMaxWidthPageSize();
maxHeightPageSize = calculator.getOptimalMaxHeightPageSize();
for (Size size : originalPageSizes) {
pageSizes.add(calculator.calculate(size));
}
if (autoSpacing) {
prepareAutoSpacing(viewSize);
}
prepareDocLen();
preparePagesOffset();
}
public int getPagesCount() {
return pagesCount;
}
public SizeF getPageSize(int pageIndex) {
int docPage = documentPage(pageIndex);
if (docPage < 0) {
return new SizeF(0, 0);
}
return pageSizes.get(pageIndex);
}
public SizeF getScaledPageSize(int pageIndex, float zoom) {
SizeF size = getPageSize(pageIndex);
return new SizeF(size.getWidth() * zoom, size.getHeight() * zoom);
}
/**
* get page size with biggest dimension (width in vertical mode and height in horizontal mode)
*
* @return size of page
*/
public SizeF getMaxPageSize() {
return isVertical ? maxWidthPageSize : maxHeightPageSize;
}
public float getMaxPageWidth() {
return getMaxPageSize().getWidth();
}
public float getMaxPageHeight() {
return getMaxPageSize().getHeight();
}
private void prepareAutoSpacing(Size viewSize) {
pageSpacing.clear();
for (int i = 0; i < getPagesCount(); i++) {
SizeF pageSize = pageSizes.get(i);
float spacing = Math.max(0, isVertical ? viewSize.getHeight() - pageSize.getHeight() :
viewSize.getWidth() - pageSize.getWidth());
if (i < getPagesCount() - 1) {
spacing += spacingPx;
}
pageSpacing.add(spacing);
}
}
private void prepareDocLen() {
float length = 0;
for (int i = 0; i < getPagesCount(); i++) {
SizeF pageSize = pageSizes.get(i);
length += isVertical ? pageSize.getHeight() : pageSize.getWidth();
if (autoSpacing) {
length += pageSpacing.get(i);
} else if (i < getPagesCount() - 1) {
length += spacingPx;
}
}
documentLength = length;
}
private void preparePagesOffset() {
pageOffsets.clear();
float offset = 0;
for (int i = 0; i < getPagesCount(); i++) {
SizeF pageSize = pageSizes.get(i);
float size = isVertical ? pageSize.getHeight() : pageSize.getWidth();
if (autoSpacing) {
offset += pageSpacing.get(i) / 2f;
if (i == 0) {
offset -= spacingPx / 2f;
} else if (i == getPagesCount() - 1) {
offset += spacingPx / 2f;
}
pageOffsets.add(offset);
offset += size + pageSpacing.get(i) / 2f;
} else {
pageOffsets.add(offset);
offset += size + spacingPx;
}
}
}
public float getDocLen(float zoom) {
return documentLength * zoom;
}
/**
* Get the page's height if swiping vertical, or width if swiping horizontal.
*/
public float getPageLength(int pageIndex, float zoom) {
SizeF size = getPageSize(pageIndex);
return (isVertical ? size.getHeight() : size.getWidth()) * zoom;
}
public float getPageSpacing(int pageIndex, float zoom) {
float spacing = autoSpacing ? pageSpacing.get(pageIndex) : spacingPx;
return spacing * zoom;
}
/** Get primary page offset, that is Y for vertical scroll and X for horizontal scroll */
public float getPageOffset(int pageIndex, float zoom) {
int docPage = documentPage(pageIndex);
if (docPage < 0) {
return 0;
}
return pageOffsets.get(pageIndex) * zoom;
}
/** Get secondary page offset, that is X for vertical scroll and Y for horizontal scroll */
public float getSecondaryPageOffset(int pageIndex, float zoom) {
SizeF pageSize = getPageSize(pageIndex);
if (isVertical) {
float maxWidth = getMaxPageWidth();
return zoom * (maxWidth - pageSize.getWidth()) / 2; //x
} else {
float maxHeight = getMaxPageHeight();
return zoom * (maxHeight - pageSize.getHeight()) / 2; //y
}
}
public int getPageAtOffset(float offset, float zoom) {
int currentPage = 0;
for (int i = 0; i < getPagesCount(); i++) {
float off = pageOffsets.get(i) * zoom - getPageSpacing(i, zoom) / 2f;
if (off >= offset) {
break;
}
currentPage++;
}
return --currentPage >= 0 ? currentPage : 0;
}
public boolean openPage(int pageIndex) throws PageRenderingException {
int docPage = documentPage(pageIndex);
if (docPage < 0) {
return false;
}
synchronized (lock) {
if (openedPages.indexOfKey(docPage) < 0) {
try {
pdfiumCore.openPage(pdfDocument, docPage);
openedPages.put(docPage, true);
return true;
} catch (Exception e) {
openedPages.put(docPage, false);
throw new PageRenderingException(pageIndex, e);
}
}
return false;
}
}
public boolean pageHasError(int pageIndex) {
int docPage = documentPage(pageIndex);
return !openedPages.get(docPage, false);
}
public void renderPageBitmap(Bitmap bitmap, int pageIndex, Rect bounds, boolean annotationRendering) {
int docPage = documentPage(pageIndex);
pdfiumCore.renderPageBitmap(pdfDocument, bitmap, docPage,
bounds.left, bounds.top, bounds.width(), bounds.height(), annotationRendering);
}
public PdfDocument.Meta getMetaData() {
if (pdfDocument == null) {
return null;
}
return pdfiumCore.getDocumentMeta(pdfDocument);
}
public List<PdfDocument.Bookmark> getBookmarks() {
if (pdfDocument == null) {
return new ArrayList<>();
}
return pdfiumCore.getTableOfContents(pdfDocument);
}
public List<PdfDocument.Link> getPageLinks(int pageIndex) {
int docPage = documentPage(pageIndex);
return pdfiumCore.getPageLinks(pdfDocument, docPage);
}
public RectF mapRectToDevice(int pageIndex, int startX, int startY, int sizeX, int sizeY,
RectF rect) {
int docPage = documentPage(pageIndex);
return pdfiumCore.mapRectToDevice(pdfDocument, docPage, startX, startY, sizeX, sizeY, 0, rect);
}
public void dispose() {
if (pdfiumCore != null && pdfDocument != null) {
pdfiumCore.closeDocument(pdfDocument);
}
pdfDocument = null;
originalUserPages = null;
}
/**
* Given the UserPage number, this method restrict it
* to be sure it's an existing page. It takes care of
* using the user defined pages if any.
*
* @param userPage A page number.
* @return A restricted valid page number (example : -2 => 0)
*/
public int determineValidPageNumberFrom(int userPage) {
if (userPage <= 0) {
return 0;
}
if (originalUserPages != null) {
if (userPage >= originalUserPages.length) {
return originalUserPages.length - 1;
}
} else {
if (userPage >= getPagesCount()) {
return getPagesCount() - 1;
}
}
return userPage;
}
public int documentPage(int userPage) {
int documentPage = userPage;
if (originalUserPages != null) {
if (userPage < 0 || userPage >= originalUserPages.length) {
return -1;
} else {
documentPage = originalUserPages[userPage];
}
}
if (documentPage < 0 || userPage >= getPagesCount()) {
return -1;
}
return documentPage;
}
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/RenderingHandler.java
================================================
/**
* Copyright 2016 Bartosz Schiller
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import com.github.barteksc.pdfviewer.exception.PageRenderingException;
import com.github.barteksc.pdfviewer.model.PagePart;
/**
* A {@link Handler} that will process incoming {@link RenderingTask} messages
* and alert {@link PDFView#onBitmapRendered(PagePart)} when the portion of the
* PDF is ready to render.
*/
class RenderingHandler extends Handler {
/**
* {@link Message#what} kind of message this handler processes.
*/
static final int MSG_RENDER_TASK = 1;
private static final String TAG = RenderingHandler.class.getName();
private PDFView pdfView;
private RectF renderBounds = new RectF();
private Rect roundedRenderBounds = new Rect();
private Matrix renderMatrix = new Matrix();
private boolean running = false;
RenderingHandler(Looper looper, PDFView pdfView) {
super(looper);
this.pdfView = pdfView;
}
void addRenderingTask(int page, float width, float height, RectF bounds, boolean thumbnail, int cacheOrder, boolean bestQuality, boolean annotationRendering) {
RenderingTask task = new RenderingTask(width, height, bounds, page, thumbnail, cacheOrder, bestQuality, annotationRendering);
Message msg = obtainMessage(MSG_RENDER_TASK, task);
sendMessage(msg);
}
@Override
public void handleMessage(Message message) {
RenderingTask task = (RenderingTask) message.obj;
try {
final PagePart part = proceed(task);
if (part != null) {
if (running) {
pdfView.post(new Runnable() {
@Override
public void run() {
pdfView.onBitmapRendered(part);
}
});
} else {
part.getRenderedBitmap().recycle();
}
}
} catch (final PageRenderingException ex) {
pdfView.post(new Runnable() {
@Override
public void run() {
pdfView.onPageError(ex);
}
});
}
}
private PagePart proceed(RenderingTask renderingTask) throws PageRenderingException {
PdfFile pdfFile = pdfView.pdfFile;
pdfFile.openPage(renderingTask.page);
int w = Math.round(renderingTask.width);
int h = Math.round(renderingTask.height);
if (w == 0 || h == 0 || pdfFile.pageHasError(renderingTask.page)) {
return null;
}
Bitmap render;
try {
render = Bitmap.createBitmap(w, h, renderingTask.bestQuality ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Cannot create bitmap", e);
return null;
}
calculateBounds(w, h, renderingTask.bounds);
pdfFile.renderPageBitmap(render, renderingTask.page, roundedRenderBounds, renderingTask.annotationRendering);
return new PagePart(renderingTask.page, render,
renderingTask.bounds, renderingTask.thumbnail,
renderingTask.cacheOrder);
}
private void calculateBounds(int width, int height, RectF pageSliceBounds) {
renderMatrix.reset();
renderMatrix.postTranslate(-pageSliceBounds.left * width, -pageSliceBounds.top * height);
renderMatrix.postScale(1 / pageSliceBounds.width(), 1 / pageSliceBounds.height());
renderBounds.set(0, 0, width, height);
renderMatrix.mapRect(renderBounds);
renderBounds.round(roundedRenderBounds);
}
void stop() {
running = false;
}
void start() {
running = true;
}
private class RenderingTask {
float width, height;
RectF bounds;
int page;
boolean thumbnail;
int cacheOrder;
boolean bestQuality;
boolean annotationRendering;
RenderingTask(float width, float height, RectF bounds, int page, boolean thumbnail, int cacheOrder, boolean bestQuality, boolean annotationRendering) {
this.page = page;
this.width = width;
this.height = height;
this.bounds = bounds;
this.thumbnail = thumbnail;
this.cacheOrder = cacheOrder;
this.bestQuality = bestQuality;
this.annotationRendering = annotationRendering;
}
}
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/exception/FileNotFoundException.java
================================================
/**
* Copyright 2016 Bartosz Schiller
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.exception;
@Deprecated
public class FileNotFoundException extends RuntimeException {
public FileNotFoundException(String detailMessage) {
super(detailMessage);
}
public FileNotFoundException(String detailMessage, Throwable throwable) {
super(detailMessage, throwable);
}
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/exception/PageRenderingException.java
================================================
package com.github.barteksc.pdfviewer.exception;
public class PageRenderingException extends Exception {
private final int page;
public PageRenderingException(int page, Throwable cause) {
super(cause);
this.page = page;
}
public int getPage() {
return page;
}
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/link/DefaultLinkHandler.java
================================================
/**
* Copyright 2017 Bartosz Schiller
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.link;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.util.Log;
import com.github.barteksc.pdfviewer.PDFView;
import com.github.barteksc.pdfviewer.model.LinkTapEvent;
public class DefaultLinkHandler implements LinkHandler {
private static final String TAG = DefaultLinkHandler.class.getSimpleName();
private PDFView pdfView;
public DefaultLinkHandler(PDFView pdfView) {
this.pdfView = pdfView;
}
@Override
public void handleLinkEvent(LinkTapEvent event) {
String uri = event.getLink().getUri();
Integer page = event.getLink().getDestPageIdx();
if (uri != null && !uri.isEmpty()) {
handleUri(uri);
} else if (page != null) {
handlePage(page);
}
}
private void handleUri(String uri) {
Uri parsedUri = Uri.parse(uri);
Intent intent = new Intent(Intent.ACTION_VIEW, parsedUri);
Context context = pdfView.getContext();
if (intent.resolveActivity(context.getPackageManager()) != null) {
context.startActivity(intent);
} else {
Log.w(TAG, "No activity found for URI: " + uri);
}
}
private void handlePage(int page) {
pdfView.jumpTo(page);
}
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/link/LinkHandler.java
================================================
/**
* Copyright 2017 Bartosz Schiller
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.link;
import com.github.barteksc.pdfviewer.model.LinkTapEvent;
public interface LinkHandler {
/**
* Called when link was tapped by user
*
* @param event current event
*/
void handleLinkEvent(LinkTapEvent event);
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/listener/Callbacks.java
================================================
/**
* Copyright 2017 Bartosz Schiller
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.listener;
import android.view.MotionEvent;
import com.github.barteksc.pdfviewer.link.LinkHandler;
import com.github.barteksc.pdfviewer.model.LinkTapEvent;
public class Callbacks {
/**
* Call back object to call when the PDF is loaded
*/
private OnLoadCompleteListener onLoadCompleteListener;
/**
* Call back object to call when document loading error occurs
*/
private OnErrorListener onErrorListener;
/**
* Call back object to call when the page load error occurs
*/
private OnPageErrorListener onPageErrorListener;
/**
* Call back object to call when the document is initially rendered
*/
private OnRenderListener onRenderListener;
/**
* Call back object to call when the page has changed
*/
private OnPageChangeListener onPageChangeListener;
/**
* Call back object to call when the page is scrolled
*/
private OnPageScrollListener onPageScrollListener;
/**
* Call back object to call when the above layer is to drawn
*/
private OnDrawListener onDrawListener;
private OnDrawListener onDrawAllListener;
/**
* Call back object to call when the user does a tap gesture
*/
private OnTapListener onTapListener;
/**
* Call back object to call when the user does a long tap gesture
*/
private OnLongPressListener onLongPressListener;
/**
* Call back object to call when clicking link
*/
private LinkHandler linkHandler;
public void setOnLoadComplete(OnLoadCompleteListener onLoadCompleteListener) {
this.onLoadCompleteListener = onLoadCompleteListener;
}
public void callOnLoadComplete(int pagesCount) {
if (onLoadCompleteListener != null) {
onLoadCompleteListener.loadComplete(pagesCount);
}
}
public void setOnError(OnErrorListener onErrorListener) {
this.onErrorListener = onErrorListener;
}
public OnErrorListener getOnError() {
return onErrorListener;
}
public void setOnPageError(OnPageErrorListener onPageErrorListener) {
this.onPageErrorListener = onPageErrorListener;
}
public boolean callOnPageError(int page, Throwable error) {
if (onPageErrorListener != null) {
onPageErrorListener.onPageError(page, error);
return true;
}
return false;
}
public void setOnRender(OnRenderListener onRenderListener) {
this.onRenderListener = onRenderListener;
}
public void callOnRender(int pagesCount) {
if (onRenderListener != null) {
onRenderListener.onInitiallyRendered(pagesCount);
}
}
public void setOnPageChange(OnPageChangeListener onPageChangeListener) {
this.onPageChangeListener = onPageChangeListener;
}
public void callOnPageChange(int page, int pagesCount) {
if (onPageChangeListener != null) {
onPageChangeListener.onPageChanged(page, pagesCount);
}
}
public void setOnPageScroll(OnPageScrollListener onPageScrollListener) {
this.onPageScrollListener = onPageScrollListener;
}
public void callOnPageScroll(int currentPage, float offset) {
if (onPageScrollListener != null) {
onPageScrollListener.onPageScrolled(currentPage, offset);
}
}
public void setOnDraw(OnDrawListener onDrawListener) {
this.onDrawListener = onDrawListener;
}
public OnDrawListener getOnDraw() {
return onDrawListener;
}
public void setOnDrawAll(OnDrawListener onDrawAllListener) {
this.onDrawAllListener = onDrawAllListener;
}
public OnDrawListener getOnDrawAll() {
return onDrawAllListener;
}
public void setOnTap(OnTapListener onTapListener) {
this.onTapListener = onTapListener;
}
public boolean callOnTap(MotionEvent event) {
return onTapListener != null && onTapListener.onTap(event);
}
public void setOnLongPress(OnLongPressListener onLongPressListener) {
this.onLongPressListener = onLongPressListener;
}
public void callOnLongPress(MotionEvent event) {
if (onLongPressListener != null) {
onLongPressListener.onLongPress(event);
}
}
public void setLinkHandler(LinkHandler linkHandler) {
this.linkHandler = linkHandler;
}
public void callLinkHandler(LinkTapEvent event) {
if (linkHandler != null) {
linkHandler.handleLinkEvent(event);
}
}
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/listener/OnDrawListener.java
================================================
/**
* Copyright 2016 Bartosz Schiller
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.listener;
import android.graphics.Canvas;
/**
* This interface allows an extern class to draw
* something on the PDFView canvas, above all images.
*/
public interface OnDrawListener {
/**
* This method is called when the PDFView is
* drawing its view.
* <p>
* The page is starting at (0,0)
*
* @param canvas The canvas on which to draw things.
* @param pageWidth The width of the current page.
* @param pageHeight The height of the current page.
* @param displayedPage The current page index
*/
void onLayerDrawn(Canvas canvas, float pageWidth, float pageHeight, int displayedPage);
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/listener/OnErrorListener.java
================================================
/**
* Copyright 2016 Bartosz Schiller
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.listener;
public interface OnErrorListener {
/**
* Called if error occurred while opening PDF
* @param t Throwable with error
*/
void onError(Throwable t);
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/listener/OnLoadCompleteListener.java
================================================
/**
* Copyright 2016 Bartosz Schiller
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.listener;
/**
* Implement this interface to receive events from PDFView
* when loading is complete.
*/
public interface OnLoadCompleteListener {
/**
* Called when the PDF is loaded
* @param nbPages the number of pages in this PDF file
*/
void loadComplete(int nbPages);
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/listener/OnLongPressListener.java
================================================
/**
* Copyright 2017 Bartosz Schiller
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.listener;
import android.view.MotionEvent;
/**
* Implement this interface to receive events from PDFView
* when view has been long pressed
*/
public interface OnLongPressListener {
/**
* Called when the user has a long tap gesture, before processing scroll handle toggling
*
* @param e MotionEvent that registered as a confirmed long press
*/
void onLongPress(MotionEvent e);
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/listener/OnPageChangeListener.java
================================================
/**
* Copyright 2016 Bartosz Schiller
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.listener;
/**
* Implements this interface to receive events from PDFView
* when a page has changed through swipe
*/
public interface OnPageChangeListener {
/**
* Called when the user use swipe to change page
*
* @param page the new page displayed, starting from 0
* @param pageCount the total page count
*/
void onPageChanged(int page, int pageCount);
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/listener/OnPageErrorListener.java
================================================
/**
* Copyright 2017 Bartosz Schiller
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.listener;
public interface OnPageErrorListener {
/**
* Called if error occurred while loading PDF page
* @param t Throwable with error
*/
void onPageError(int page, Throwable t);
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/listener/OnPageScrollListener.java
================================================
/**
* Copyright 2016 Bartosz Schiller
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.listener;
/**
* Implements this interface to receive events from PDFView
* when a page has been scrolled
*/
public interface OnPageScrollListener {
/**
* Called on every move while scrolling
*
* @param page current page index
* @param positionOffset see {@link com.github.barteksc.pdfviewer.PDFView#getPositionOffset()}
*/
void onPageScrolled(int page, float positionOffset);
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/listener/OnRenderListener.java
================================================
/**
* Copyright 2017 Bartosz Schiller
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.listener;
public interface OnRenderListener {
/**
* Called only once, when document is rendered
* @param nbPages number of pages
*/
void onInitiallyRendered(int nbPages);
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/listener/OnTapListener.java
================================================
/**
* Copyright 2017 Bartosz Schiller
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.listener;
import android.view.MotionEvent;
/**
* Implement this interface to receive events from PDFView
* when view has been touched
*/
public interface OnTapListener {
/**
* Called when the user has a tap gesture, before processing scroll handle toggling
*
* @param e MotionEvent that registered as a confirmed single tap
* @return true if the single tap was handled, false to toggle scroll handle
*/
boolean onTap(MotionEvent e);
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/model/LinkTapEvent.java
================================================
/**
* Copyright 2016 Bartosz Schiller
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.model;
import android.graphics.RectF;
import com.shockwave.pdfium.PdfDocument;
public class LinkTapEvent {
private float originalX;
private float originalY;
private float documentX;
private float documentY;
private RectF mappedLinkRect;
private PdfDocument.Link link;
public LinkTapEvent(float originalX, float originalY, float documentX, float documentY, RectF mappedLinkRect, PdfDocument.Link link) {
this.originalX = originalX;
this.originalY = originalY;
this.documentX = documentX;
this.documentY = documentY;
this.mappedLinkRect = mappedLinkRect;
this.link = link;
}
public float getOriginalX() {
return originalX;
}
public float getOriginalY() {
return originalY;
}
public float getDocumentX() {
return documentX;
}
public float getDocumentY() {
return documentY;
}
public RectF getMappedLinkRect() {
return mappedLinkRect;
}
public PdfDocument.Link getLink() {
return link;
}
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/model/PagePart.java
================================================
/**
* Copyright 2016 Bartosz Schiller
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.model;
import android.graphics.Bitmap;
import android.graphics.RectF;
public class PagePart {
private int page;
private Bitmap renderedBitmap;
private RectF pageRelativeBounds;
private boolean thumbnail;
private int cacheOrder;
public PagePart(int page, Bitmap renderedBitmap, RectF pageRelativeBounds, boolean thumbnail, int cacheOrder) {
super();
this.page = page;
this.renderedBitmap = renderedBitmap;
this.pageRelativeBounds = pageRelativeBounds;
this.thumbnail = thumbnail;
this.cacheOrder = cacheOrder;
}
public int getCacheOrder() {
return cacheOrder;
}
public int getPage() {
return page;
}
public Bitmap getRenderedBitmap() {
return renderedBitmap;
}
public RectF getPageRelativeBounds() {
return pageRelativeBounds;
}
public boolean isThumbnail() {
return thumbnail;
}
public void setCacheOrder(int cacheOrder) {
this.cacheOrder = cacheOrder;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof PagePart)) {
return false;
}
PagePart part = (PagePart) obj;
return part.getPage() == page
&& part.getPageRelativeBounds().left == pageRelativeBounds.left
&& part.getPageRelativeBounds().right == pageRelativeBounds.right
&& part.getPageRelativeBounds().top == pageRelativeBounds.top
&& part.getPageRelativeBounds().bottom == pageRelativeBounds.bottom;
}
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/scroll/DefaultScrollHandle.java
================================================
package com.github.barteksc.pdfviewer.scroll;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import androidx.core.content.ContextCompat;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.github.barteksc.pdfviewer.PDFView;
import com.github.barteksc.pdfviewer.R;
import com.github.barteksc.pdfviewer.util.Util;
public class DefaultScrollHandle extends RelativeLayout implements ScrollHandle {
private final static int HANDLE_LONG = 65;
private final static int HANDLE_SHORT = 40;
private final static int DEFAULT_TEXT_SIZE = 16;
private float relativeHandlerMiddle = 0f;
protected TextView textView;
protected Context context;
private boolean inverted;
private PDFView pdfView;
private float currentPos;
private Handler handler = new Handler();
private Runnable hidePageScrollerRunnable = new Runnable() {
@Override
public void run() {
hide();
}
};
public DefaultScrollHandle(Context context) {
this(context, false);
}
public DefaultScrollHandle(Context context, boolean inverted) {
super(context);
this.context = context;
this.inverted = inverted;
textView = new TextView(context);
setVisibility(INVISIBLE);
setTextColor(Color.BLACK);
setTextSize(DEFAULT_TEXT_SIZE);
}
@Override
public void setupLayout(PDFView pdfView) {
int align, width, height;
Drawable background;
// determine handler position, default is right (when scrolling vertically) or bottom (when scrolling horizontally)
if (pdfView.isSwipeVertical()) {
width = HANDLE_LONG;
height = HANDLE_SHORT;
if (inverted) { // left
align = ALIGN_PARENT_LEFT;
background = ContextCompat.getDrawable(context, R.drawable.default_scroll_handle_left);
} else { // right
align = ALIGN_PARENT_RIGHT;
background = ContextCompat.getDrawable(context, R.drawable.default_scroll_handle_right);
}
} else {
width = HANDLE_SHORT;
height = HANDLE_LONG;
if (inverted) { // top
align = ALIGN_PARENT_TOP;
background = ContextCompat.getDrawable(context, R.drawable.default_scroll_handle_top);
} else { // bottom
align = ALIGN_PARENT_BOTTOM;
background = ContextCompat.getDrawable(context, R.drawable.default_scroll_handle_bottom);
}
}
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN) {
setBackgroundDrawable(background);
} else {
setBackground(background);
}
LayoutParams lp = new LayoutParams(Util.getDP(context, width), Util.getDP(context, height));
lp.setMargins(0, 0, 0, 0);
LayoutParams tvlp = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
tvlp.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
addView(textView, tvlp);
lp.addRule(align);
pdfView.addView(this, lp);
this.pdfView = pdfView;
}
@Override
public void destroyLayout() {
pdfView.removeView(this);
}
@Override
public void setScroll(float position) {
if (!shown()) {
show();
} else {
handler.removeCallbacks(hidePageScrollerRunnable);
}
if (pdfView != null) {
setPosition((pdfView.isSwipeVertical() ? pdfView.getHeight() : pdfView.getWidth()) * position);
}
}
private void setPosition(float pos) {
if (Float.isInfinite(pos) || Float.isNaN(pos)) {
return;
}
float pdfViewSize;
if (pdfView.isSwipeVertical()) {
pdfViewSize = pdfView.getHeight();
} else {
pdfViewSize = pdfView.getWidth();
}
pos -= relativeHandlerMiddle;
if (pos < 0) {
pos = 0;
} else if (pos > pdfViewSize - Util.getDP(context, HANDLE_SHORT)) {
pos = pdfViewSize - Util.getDP(context, HANDLE_SHORT);
}
if (pdfView.isSwipeVertical()) {
setY(pos);
} else {
setX(pos);
}
calculateMiddle();
invalidate();
}
private void calculateMiddle() {
float pos, viewSize, pdfViewSize;
if (pdfView.isSwipeVertical()) {
pos = getY();
viewSize = getHeight();
pdfViewSize = pdfView.getHeight();
} else {
pos = getX();
viewSize = getWidth();
pdfViewSize = pdfView.getWidth();
}
relativeHandlerMiddle = ((pos + relativeHandlerMiddle) / pdfViewSize) * viewSize;
}
@Override
public void hideDelayed() {
handler.postDelayed(hidePageScrollerRunnable, 1000);
}
@Override
public void setPageNum(int pageNum) {
String text = String.valueOf(pageNum);
if (!textView.getText().equals(text)) {
textView.setText(text);
}
}
@Override
public boolean shown() {
return getVisibility() == VISIBLE;
}
@Override
public void show() {
setVisibility(VISIBLE);
}
@Override
public void hide() {
setVisibility(INVISIBLE);
}
public void setTextColor(int color) {
textView.setTextColor(color);
}
/**
* @param size text size in dp
*/
public void setTextSize(int size) {
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, size);
}
private boolean isPDFViewReady() {
return pdfView != null && pdfView.getPageCount() > 0 && !pdfView.documentFitsView();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (!isPDFViewReady()) {
return super.onTouchEvent(event);
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
pdfView.stopFling();
handler.removeCallbacks(hidePageScrollerRunnable);
if (pdfView.isSwipeVertical()) {
currentPos = event.getRawY() - getY();
} else {
currentPos = event.getRawX() - getX();
}
case MotionEvent.ACTION_MOVE:
if (pdfView.isSwipeVertical()) {
setPosition(event.getRawY() - currentPos + relativeHandlerMiddle);
pdfView.setPositionOffset(relativeHandlerMiddle / (float) getHeight(), false);
} else {
setPosition(event.getRawX() - currentPos + relativeHandlerMiddle);
pdfView.setPositionOffset(relativeHandlerMiddle / (float) getWidth(), false);
}
return true;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
hideDelayed();
pdfView.performPageSnap();
return true;
}
return super.onTouchEvent(event);
}
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/scroll/ScrollHandle.java
================================================
package com.github.barteksc.pdfviewer.scroll;
import com.github.barteksc.pdfviewer.PDFView;
public interface ScrollHandle {
/**
* Used to move the handle, called internally by PDFView
*
* @param position current scroll ratio between 0 and 1
*/
void setScroll(float position);
/**
* Method called by PDFView after setting scroll handle.
* Do not call this method manually.
* For usage sample see {@link DefaultScrollHandle}
*
* @param pdfView PDFView instance
*/
void setupLayout(PDFView pdfView);
/**
* Method called by PDFView when handle should be removed from layout
* Do not call this method manually.
*/
void destroyLayout();
/**
* Set page number displayed on handle
*
* @param pageNum page number
*/
void setPageNum(int pageNum);
/**
* Get handle visibility
*
* @return true if handle is visible, false otherwise
*/
boolean shown();
/**
* Show handle
*/
void show();
/**
* Hide handle immediately
*/
void hide();
/**
* Hide handle after some time (defined by implementation)
*/
void hideDelayed();
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/source/AssetSource.java
================================================
/*
* Copyright (C) 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.source;
import android.content.Context;
import android.os.ParcelFileDescriptor;
import com.github.barteksc.pdfviewer.util.FileUtils;
import com.shockwave.pdfium.PdfDocument;
import com.shockwave.pdfium.PdfiumCore;
import java.io.File;
import java.io.IOException;
public class AssetSource implements DocumentSource {
private final String assetName;
public AssetSource(String assetName) {
this.assetName = assetName;
}
@Override
public PdfDocument createDocument(Context context, PdfiumCore core, String password) throws IOException {
File f = FileUtils.fileFromAsset(context, assetName);
ParcelFileDescriptor pfd = ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY);
return core.newDocument(pfd, password);
}
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/source/ByteArraySource.java
================================================
/*
* Copyright (C) 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.source;
import android.content.Context;
import com.shockwave.pdfium.PdfDocument;
import com.shockwave.pdfium.PdfiumCore;
import java.io.IOException;
public class ByteArraySource implements DocumentSource {
private byte[] data;
public ByteArraySource(byte[] data) {
this.data = data;
}
@Override
public PdfDocument createDocument(Context context, PdfiumCore core, String password) throws IOException {
return core.newDocument(data, password);
}
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/source/DocumentSource.java
================================================
/*
* Copyright (C) 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.source;
import android.content.Context;
import com.shockwave.pdfium.PdfDocument;
import com.shockwave.pdfium.PdfiumCore;
import java.io.IOException;
public interface DocumentSource {
PdfDocument createDocument(Context context, PdfiumCore core, String password) throws IOException;
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/source/FileSource.java
================================================
/*
* Copyright (C) 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.source;
import android.content.Context;
import android.os.ParcelFileDescriptor;
import com.shockwave.pdfium.PdfDocument;
import com.shockwave.pdfium.PdfiumCore;
import java.io.File;
import java.io.IOException;
public class FileSource implements DocumentSource {
private File file;
public FileSource(File file) {
this.file = file;
}
@Override
public PdfDocument createDocument(Context context, PdfiumCore core, String password) throws IOException {
ParcelFileDescriptor pfd = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
return core.newDocument(pfd, password);
}
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/source/InputStreamSource.java
================================================
/*
* Copyright (C) 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.source;
import android.content.Context;
import com.github.barteksc.pdfviewer.util.Util;
import com.shockwave.pdfium.PdfDocument;
import com.shockwave.pdfium.PdfiumCore;
import java.io.IOException;
import java.io.InputStream;
public class InputStreamSource implements DocumentSource {
private InputStream inputStream;
public InputStreamSource(InputStream inputStream) {
this.inputStream = inputStream;
}
@Override
public PdfDocument createDocument(Context context, PdfiumCore core, String password) throws IOException {
return core.newDocument(Util.toByteArray(inputStream), password);
}
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/source/UriSource.java
================================================
/*
* Copyright (C) 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.source;
import android.content.Context;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import com.shockwave.pdfium.PdfDocument;
import com.shockwave.pdfium.PdfiumCore;
import java.io.IOException;
public class UriSource implements DocumentSource {
private Uri uri;
public UriSource(Uri uri) {
this.uri = uri;
}
@Override
public PdfDocument createDocument(Context context, PdfiumCore core, String password) throws IOException {
ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(uri, "r");
return core.newDocument(pfd, password);
}
}
================================================
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/util/ArrayUtils.java
================================================
/**
* Copyright 2016 Bartosz Schiller
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.util;
import java.util.ArrayList;
import java.util.List;
public class ArrayUtils {
private ArrayUtils() {
// Prevents instantiation
}
/** Transforms (0,1,2,2,3) to (0,1,2,3) */
public static int[] deleteDuplicatedPages(int[] pages) {
List<Integer> result = new ArrayList<>();
int lastInt = -1;
for (Integer currentInt : pages) {
if (lastInt != currentInt) {
result.add(currentInt);
}
lastInt = currentInt;
}
int[] arrayResult = new int[result.size()];
for (int i = 0; i < result.size(); i++) {
arrayResult[i] = result.get(i);
}
return arrayResult;
}
/** Transforms (0, 4, 4, 6, 6, 6, 3) into (0, 1, 1, 2, 2, 2, 3) */
public static int[] calculateIndexesInDuplicateArray(int[] originalUserPages) {
int[] result = new int[originalUserPages.length];
if (originalUserPages.length == 0) {
return result;
}
int index = 0;
result[0] = index;
for (int i = 1; i < originalUserPages.length; i++) {
if (originalUserPages[i] != originalUserPages[i - 1]) {
index++;
}
result[i] = index;
}
return result;
}
public static String arrayToString
gitextract_l2u_xl7x/ ├── .gitignore ├── 16KB_SUPPORT.md ├── CHANGELOG.md ├── LICENSE ├── README.md ├── android-pdf-viewer/ │ ├── bintray.gradle │ ├── build.gradle │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── java/ │ │ └── com/ │ │ └── github/ │ │ └── barteksc/ │ │ └── pdfviewer/ │ │ ├── AnimationManager.java │ │ ├── CacheManager.java │ │ ├── DecodingAsyncTask.java │ │ ├── DragPinchManager.java │ │ ├── PDFView.java │ │ ├── PagesLoader.java │ │ ├── PdfFile.java │ │ ├── RenderingHandler.java │ │ ├── exception/ │ │ │ ├── FileNotFoundException.java │ │ │ └── PageRenderingException.java │ │ ├── link/ │ │ │ ├── DefaultLinkHandler.java │ │ │ └── LinkHandler.java │ │ ├── listener/ │ │ │ ├── Callbacks.java │ │ │ ├── OnDrawListener.java │ │ │ ├── OnErrorListener.java │ │ │ ├── OnLoadCompleteListener.java │ │ │ ├── OnLongPressListener.java │ │ │ ├── OnPageChangeListener.java │ │ │ ├── OnPageErrorListener.java │ │ │ ├── OnPageScrollListener.java │ │ │ ├── OnRenderListener.java │ │ │ └── OnTapListener.java │ │ ├── model/ │ │ │ ├── LinkTapEvent.java │ │ │ └── PagePart.java │ │ ├── scroll/ │ │ │ ├── DefaultScrollHandle.java │ │ │ └── ScrollHandle.java │ │ ├── source/ │ │ │ ├── AssetSource.java │ │ │ ├── ByteArraySource.java │ │ │ ├── DocumentSource.java │ │ │ ├── FileSource.java │ │ │ ├── InputStreamSource.java │ │ │ └── UriSource.java │ │ └── util/ │ │ ├── ArrayUtils.java │ │ ├── Constants.java │ │ ├── FileUtils.java │ │ ├── FitPolicy.java │ │ ├── MathUtils.java │ │ ├── PageSizeCalculator.java │ │ ├── SnapEdge.java │ │ └── Util.java │ └── res/ │ ├── drawable/ │ │ ├── default_scroll_handle_bottom.xml │ │ ├── default_scroll_handle_left.xml │ │ ├── default_scroll_handle_right.xml │ │ └── default_scroll_handle_top.xml │ └── values/ │ └── attrs.xml ├── build.gradle ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat ├── sample/ │ ├── build.gradle │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── java/ │ │ └── com/ │ │ └── github/ │ │ └── barteksc/ │ │ └── sample/ │ │ └── PDFViewActivity.java │ └── res/ │ ├── layout/ │ │ └── activity_main.xml │ ├── menu/ │ │ └── options.xml │ └── values/ │ ├── strings.xml │ └── styles.xml └── settings.gradle
SYMBOL INDEX (424 symbols across 41 files)
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/AnimationManager.java
class AnimationManager (line 34) | class AnimationManager {
method AnimationManager (line 46) | public AnimationManager(PDFView pdfView) {
method startXAnimation (line 51) | public void startXAnimation(float xFrom, float xTo) {
method startYAnimation (line 62) | public void startYAnimation(float yFrom, float yTo) {
method startZoomAnimation (line 73) | public void startZoomAnimation(float centerX, float centerY, float zoo...
method startFlingAnimation (line 84) | public void startFlingAnimation(int startX, int startY, int velocityX,...
method startPageFlingAnimation (line 90) | public void startPageFlingAnimation(float targetOffset) {
method computeFling (line 99) | void computeFling() {
method stopAll (line 111) | public void stopAll() {
method stopFling (line 119) | public void stopFling() {
method isFlinging (line 124) | public boolean isFlinging() {
class XAnimation (line 128) | class XAnimation extends AnimatorListenerAdapter implements AnimatorUp...
method onAnimationUpdate (line 130) | @Override
method onAnimationCancel (line 137) | @Override
method onAnimationEnd (line 144) | @Override
class YAnimation (line 152) | class YAnimation extends AnimatorListenerAdapter implements AnimatorUp...
method onAnimationUpdate (line 154) | @Override
method onAnimationCancel (line 161) | @Override
method onAnimationEnd (line 168) | @Override
class ZoomAnimation (line 176) | class ZoomAnimation implements AnimatorUpdateListener, AnimatorListener {
method ZoomAnimation (line 181) | public ZoomAnimation(float centerX, float centerY) {
method onAnimationUpdate (line 186) | @Override
method onAnimationCancel (line 192) | @Override
method onAnimationEnd (line 198) | @Override
method onAnimationRepeat (line 205) | @Override
method onAnimationStart (line 209) | @Override
method hideHandle (line 215) | private void hideHandle() {
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/CacheManager.java
class CacheManager (line 32) | class CacheManager {
method CacheManager (line 44) | public CacheManager() {
method cachePart (line 50) | public void cachePart(PagePart part) {
method makeANewSet (line 60) | public void makeANewSet() {
method makeAFreeSpace (line 67) | private void makeAFreeSpace() {
method cacheThumbnail (line 82) | public void cacheThumbnail(PagePart part) {
method upPartIfContained (line 95) | public boolean upPartIfContained(int page, RectF pageRelativeBounds, i...
method containsThumbnail (line 114) | public boolean containsThumbnail(int page, RectF pageRelativeBounds) {
method addWithoutDuplicates (line 129) | private void addWithoutDuplicates(Collection<PagePart> collection, Pag...
method find (line 139) | @Nullable
method getPageParts (line 149) | public List<PagePart> getPageParts() {
method getThumbnails (line 157) | public List<PagePart> getThumbnails() {
method recycle (line 163) | public void recycle() {
class PagePartComparator (line 182) | class PagePartComparator implements Comparator<PagePart> {
method compare (line 183) | @Override
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/DecodingAsyncTask.java
class DecodingAsyncTask (line 27) | class DecodingAsyncTask extends AsyncTask<Void, Void, Throwable> {
method DecodingAsyncTask (line 39) | DecodingAsyncTask(DocumentSource docSource, String password, int[] use...
method doInBackground (line 48) | @Override
method getViewSize (line 67) | private Size getViewSize(PDFView pdfView) {
method onPostExecute (line 71) | @Override
method onCancelled (line 85) | @Override
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/DragPinchManager.java
class DragPinchManager (line 38) | class DragPinchManager implements GestureDetector.OnGestureListener, Ges...
method DragPinchManager (line 50) | DragPinchManager(PDFView pdfView, AnimationManager animationManager) {
method enable (line 58) | void enable() {
method disable (line 62) | void disable() {
method disableLongpress (line 66) | void disableLongpress(){
method onSingleTapConfirmed (line 70) | @Override
method checkLinkTapped (line 88) | private boolean checkLinkTapped(float x, float y) {
method startPageFling (line 117) | private void startPageFling(MotionEvent downEvent, MotionEvent ev, flo...
method onDoubleTap (line 140) | @Override
method onDoubleTapEvent (line 156) | @Override
method onDown (line 161) | @Override
method onShowPress (line 167) | @Override
method onSingleTapUp (line 172) | @Override
method onScroll (line 177) | @Override
method onScrollEnd (line 189) | private void onScrollEnd(MotionEvent event) {
method onLongPress (line 197) | @Override
method onFling (line 202) | @Override
method onBoundedFling (line 234) | private void onBoundedFling(float velocityX, float velocityY) {
method onScale (line 259) | @Override
method onScaleBegin (line 274) | @Override
method onScaleEnd (line 280) | @Override
method onTouch (line 287) | @Override
method hideHandle (line 305) | private void hideHandle() {
method checkDoPageFling (line 312) | private boolean checkDoPageFling(float velocityX, float velocityY) {
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/PDFView.java
class PDFView (line 94) | public class PDFView extends RelativeLayout {
type ScrollDir (line 111) | enum ScrollDir {
method getScrollHandle (line 197) | ScrollHandle getScrollHandle() {
method PDFView (line 245) | public PDFView(Context context, AttributeSet set) {
method load (line 267) | private void load(DocumentSource docSource, String password) {
method load (line 271) | private void load(DocumentSource docSource, String password, int[] use...
method jumpTo (line 288) | public void jumpTo(int page, boolean withAnimation) {
method jumpTo (line 311) | public void jumpTo(int page) {
method showPage (line 315) | void showPage(int pageNb) {
method getPositionOffset (line 340) | public float getPositionOffset() {
method setPositionOffset (line 355) | public void setPositionOffset(float progress, boolean moveHandle) {
method setPositionOffset (line 364) | public void setPositionOffset(float progress) {
method stopFling (line 368) | public void stopFling() {
method getPageCount (line 372) | public int getPageCount() {
method setSwipeEnabled (line 379) | public void setSwipeEnabled(boolean enableSwipe) {
method setNightMode (line 383) | public void setNightMode(boolean nightMode) {
method enableDoubletap (line 400) | void enableDoubletap(boolean enableDoubletap) {
method isDoubletapEnabled (line 404) | boolean isDoubletapEnabled() {
method onPageError (line 408) | void onPageError(PageRenderingException ex) {
method recycle (line 414) | public void recycle() {
method isRecycled (line 451) | public boolean isRecycled() {
method computeScroll (line 456) | @Override
method onDetachedFromWindow (line 465) | @Override
method onSizeChanged (line 479) | @Override
method canScrollHorizontally (line 518) | @Override
method canScrollVertically (line 540) | @Override
method onDraw (line 562) | @Override
method drawWithListener (line 648) | private void drawWithListener(Canvas canvas, int page, OnDrawListener ...
method drawPart (line 671) | private void drawPart(Canvas canvas, PagePart part) {
method loadPages (line 737) | public void loadPages() {
method loadComplete (line 751) | void loadComplete(PdfFile pdfFile) {
method loadError (line 774) | void loadError(Throwable t) {
method redraw (line 787) | void redraw() {
method onBitmapRendered (line 797) | public void onBitmapRendered(PagePart part) {
method moveTo (line 812) | public void moveTo(float offsetX, float offsetY) {
method moveTo (line 824) | public void moveTo(float offsetX, float offsetY, boolean moveHandle) {
method loadPageByOffset (line 904) | void loadPageByOffset() {
method performPageSnap (line 930) | public void performPageSnap() {
method findSnapEdge (line 951) | SnapEdge findSnapEdge(int page) {
method snapOffsetForPage (line 974) | float snapOffsetForPage(int pageIndex, SnapEdge edge) {
method findFocusPage (line 988) | int findFocusPage(float xOffset, float yOffset) {
method pageFillsScreen (line 1005) | public boolean pageFillsScreen() {
method moveRelativeTo (line 1022) | public void moveRelativeTo(float dx, float dy) {
method zoomTo (line 1029) | public void zoomTo(float zoom) {
method zoomCenteredTo (line 1041) | public void zoomCenteredTo(float zoom, PointF pivot) {
method zoomCenteredRelativeTo (line 1054) | public void zoomCenteredRelativeTo(float dzoom, PointF pivot) {
method documentFitsView (line 1063) | public boolean documentFitsView() {
method fitToWidth (line 1072) | public void fitToWidth(int page) {
method getPageSize (line 1081) | public SizeF getPageSize(int pageIndex) {
method getCurrentPage (line 1088) | public int getCurrentPage() {
method getCurrentXOffset (line 1092) | public float getCurrentXOffset() {
method getCurrentYOffset (line 1096) | public float getCurrentYOffset() {
method toRealScale (line 1100) | public float toRealScale(float size) {
method toCurrentScale (line 1104) | public float toCurrentScale(float size) {
method getZoom (line 1108) | public float getZoom() {
method isZooming (line 1112) | public boolean isZooming() {
method setDefaultPage (line 1116) | private void setDefaultPage(int defaultPage) {
method resetZoom (line 1120) | public void resetZoom() {
method resetZoomWithAnimation (line 1124) | public void resetZoomWithAnimation() {
method zoomWithAnimation (line 1128) | public void zoomWithAnimation(float centerX, float centerY, float scal...
method zoomWithAnimation (line 1132) | public void zoomWithAnimation(float scale) {
method setScrollHandle (line 1136) | private void setScrollHandle(ScrollHandle scrollHandle) {
method getPageAtPositionOffset (line 1146) | public int getPageAtPositionOffset(float positionOffset) {
method getMinZoom (line 1150) | public float getMinZoom() {
method setMinZoom (line 1154) | public void setMinZoom(float minZoom) {
method getMidZoom (line 1158) | public float getMidZoom() {
method setMidZoom (line 1162) | public void setMidZoom(float midZoom) {
method getMaxZoom (line 1166) | public float getMaxZoom() {
method setMaxZoom (line 1170) | public void setMaxZoom(float maxZoom) {
method useBestQuality (line 1174) | public void useBestQuality(boolean bestQuality) {
method isBestQuality (line 1178) | public boolean isBestQuality() {
method isSwipeVertical (line 1182) | public boolean isSwipeVertical() {
method isSwipeEnabled (line 1186) | public boolean isSwipeEnabled() {
method setSwipeVertical (line 1190) | private void setSwipeVertical(boolean swipeVertical) {
method enableAnnotationRendering (line 1194) | public void enableAnnotationRendering(boolean annotationRendering) {
method isAnnotationRendering (line 1198) | public boolean isAnnotationRendering() {
method enableRenderDuringScale (line 1202) | public void enableRenderDuringScale(boolean renderDuringScale) {
method isAntialiasing (line 1206) | public boolean isAntialiasing() {
method enableAntialiasing (line 1210) | public void enableAntialiasing(boolean enableAntialiasing) {
method getSpacingPx (line 1214) | public int getSpacingPx() {
method isAutoSpacingEnabled (line 1218) | public boolean isAutoSpacingEnabled() {
method setPageFling (line 1222) | public void setPageFling(boolean pageFling) {
method isPageFlingEnabled (line 1226) | public boolean isPageFlingEnabled() {
method setSpacing (line 1230) | private void setSpacing(int spacingDp) {
method setAutoSpacing (line 1234) | private void setAutoSpacing(boolean autoSpacing) {
method setPageFitPolicy (line 1238) | private void setPageFitPolicy(FitPolicy pageFitPolicy) {
method getPageFitPolicy (line 1242) | public FitPolicy getPageFitPolicy() {
method setFitEachPage (line 1246) | private void setFitEachPage(boolean fitEachPage) {
method isFitEachPage (line 1250) | public boolean isFitEachPage() {
method isPageSnap (line 1254) | public boolean isPageSnap() {
method setPageSnap (line 1258) | public void setPageSnap(boolean pageSnap) {
method doRenderDuringScale (line 1262) | public boolean doRenderDuringScale() {
method getDocumentMeta (line 1267) | public PdfDocument.Meta getDocumentMeta() {
method getTableOfContents (line 1275) | public List<PdfDocument.Bookmark> getTableOfContents() {
method getLinks (line 1283) | public List<PdfDocument.Link> getLinks(int page) {
method fromAsset (line 1291) | public Configurator fromAsset(String assetName) {
method fromFile (line 1296) | public Configurator fromFile(File file) {
method fromUri (line 1301) | public Configurator fromUri(Uri uri) {
method fromBytes (line 1306) | public Configurator fromBytes(byte[] bytes) {
method fromStream (line 1311) | public Configurator fromStream(InputStream stream) {
method fromSource (line 1316) | public Configurator fromSource(DocumentSource docSource) {
type State (line 1320) | private enum State {DEFAULT, LOADED, SHOWN, ERROR}
class Configurator (line 1322) | public class Configurator {
method Configurator (line 1380) | private Configurator(DocumentSource documentSource) {
method pages (line 1384) | public Configurator pages(int... pageNumbers) {
method enableSwipe (line 1389) | public Configurator enableSwipe(boolean enableSwipe) {
method enableDoubletap (line 1394) | public Configurator enableDoubletap(boolean enableDoubletap) {
method enableAnnotationRendering (line 1399) | public Configurator enableAnnotationRendering(boolean annotationRend...
method onDraw (line 1404) | public Configurator onDraw(OnDrawListener onDrawListener) {
method onDrawAll (line 1409) | public Configurator onDrawAll(OnDrawListener onDrawAllListener) {
method onLoad (line 1414) | public Configurator onLoad(OnLoadCompleteListener onLoadCompleteList...
method onPageScroll (line 1419) | public Configurator onPageScroll(OnPageScrollListener onPageScrollLi...
method onError (line 1424) | public Configurator onError(OnErrorListener onErrorListener) {
method onPageError (line 1429) | public Configurator onPageError(OnPageErrorListener onPageErrorListe...
method onPageChange (line 1434) | public Configurator onPageChange(OnPageChangeListener onPageChangeLi...
method onRender (line 1439) | public Configurator onRender(OnRenderListener onRenderListener) {
method onTap (line 1444) | public Configurator onTap(OnTapListener onTapListener) {
method onLongPress (line 1449) | public Configurator onLongPress(OnLongPressListener onLongPressListe...
method linkHandler (line 1454) | public Configurator linkHandler(LinkHandler linkHandler) {
method defaultPage (line 1459) | public Configurator defaultPage(int defaultPage) {
method swipeHorizontal (line 1464) | public Configurator swipeHorizontal(boolean swipeHorizontal) {
method password (line 1469) | public Configurator password(String password) {
method scrollHandle (line 1474) | public Configurator scrollHandle(ScrollHandle scrollHandle) {
method enableAntialiasing (line 1479) | public Configurator enableAntialiasing(boolean antialiasing) {
method spacing (line 1484) | public Configurator spacing(int spacing) {
method autoSpacing (line 1489) | public Configurator autoSpacing(boolean autoSpacing) {
method pageFitPolicy (line 1494) | public Configurator pageFitPolicy(FitPolicy pageFitPolicy) {
method fitEachPage (line 1499) | public Configurator fitEachPage(boolean fitEachPage) {
method pageSnap (line 1504) | public Configurator pageSnap(boolean pageSnap) {
method pageFling (line 1509) | public Configurator pageFling(boolean pageFling) {
method nightMode (line 1514) | public Configurator nightMode(boolean nightMode) {
method disableLongpress (line 1519) | public Configurator disableLongpress() {
method load (line 1524) | public void load() {
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/PagesLoader.java
class PagesLoader (line 31) | class PagesLoader {
class Holder (line 44) | private class Holder {
method toString (line 48) | @Override
class RenderRange (line 57) | private class RenderRange {
method RenderRange (line 63) | RenderRange() {
method toString (line 70) | @Override
class GridSize (line 81) | private class GridSize {
method toString (line 85) | @Override
method PagesLoader (line 94) | PagesLoader(PDFView pdfView) {
method getPageColsRows (line 99) | private void getPageColsRows(GridSize grid, int pageIndex) {
method calculatePartSize (line 109) | private void calculatePartSize(GridSize grid) {
method getRenderRangeList (line 120) | private List<RenderRange> getRenderRangeList(float firstXOffset, float...
method loadVisible (line 227) | private void loadVisible() {
method loadPage (line 251) | private int loadPage(int page, int firstRow, int lastRow, int firstCol...
method loadCell (line 267) | private boolean loadCell(int page, int row, int col, float pageRelativ...
method loadThumbnail (line 299) | private void loadThumbnail(int page) {
method loadPages (line 310) | void loadPages() {
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/PdfFile.java
class PdfFile (line 34) | class PdfFile {
method PdfFile (line 78) | PdfFile(PdfiumCore pdfiumCore, PdfDocument pdfDocument, FitPolicy page...
method setup (line 91) | private void setup(Size viewSize) {
method recalculatePageSizes (line 117) | public void recalculatePageSizes(Size viewSize) {
method getPagesCount (line 134) | public int getPagesCount() {
method getPageSize (line 138) | public SizeF getPageSize(int pageIndex) {
method getScaledPageSize (line 146) | public SizeF getScaledPageSize(int pageIndex, float zoom) {
method getMaxPageSize (line 156) | public SizeF getMaxPageSize() {
method getMaxPageWidth (line 160) | public float getMaxPageWidth() {
method getMaxPageHeight (line 164) | public float getMaxPageHeight() {
method prepareAutoSpacing (line 168) | private void prepareAutoSpacing(Size viewSize) {
method prepareDocLen (line 181) | private void prepareDocLen() {
method preparePagesOffset (line 195) | private void preparePagesOffset() {
method getDocLen (line 217) | public float getDocLen(float zoom) {
method getPageLength (line 224) | public float getPageLength(int pageIndex, float zoom) {
method getPageSpacing (line 229) | public float getPageSpacing(int pageIndex, float zoom) {
method getPageOffset (line 235) | public float getPageOffset(int pageIndex, float zoom) {
method getSecondaryPageOffset (line 244) | public float getSecondaryPageOffset(int pageIndex, float zoom) {
method getPageAtOffset (line 255) | public int getPageAtOffset(float offset, float zoom) {
method openPage (line 267) | public boolean openPage(int pageIndex) throws PageRenderingException {
method pageHasError (line 288) | public boolean pageHasError(int pageIndex) {
method renderPageBitmap (line 293) | public void renderPageBitmap(Bitmap bitmap, int pageIndex, Rect bounds...
method getMetaData (line 299) | public PdfDocument.Meta getMetaData() {
method getBookmarks (line 306) | public List<PdfDocument.Bookmark> getBookmarks() {
method getPageLinks (line 313) | public List<PdfDocument.Link> getPageLinks(int pageIndex) {
method mapRectToDevice (line 318) | public RectF mapRectToDevice(int pageIndex, int startX, int startY, in...
method dispose (line 324) | public void dispose() {
method determineValidPageNumberFrom (line 341) | public int determineValidPageNumberFrom(int userPage) {
method documentPage (line 357) | public int documentPage(int userPage) {
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/RenderingHandler.java
class RenderingHandler (line 36) | class RenderingHandler extends Handler {
method RenderingHandler (line 51) | RenderingHandler(Looper looper, PDFView pdfView) {
method addRenderingTask (line 56) | void addRenderingTask(int page, float width, float height, RectF bound...
method handleMessage (line 62) | @Override
method proceed (line 89) | private PagePart proceed(RenderingTask renderingTask) throws PageRende...
method calculateBounds (line 116) | private void calculateBounds(int width, int height, RectF pageSliceBou...
method stop (line 126) | void stop() {
method start (line 130) | void start() {
class RenderingTask (line 134) | private class RenderingTask {
method RenderingTask (line 150) | RenderingTask(float width, float height, RectF bounds, int page, boo...
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/exception/FileNotFoundException.java
class FileNotFoundException (line 18) | @Deprecated
method FileNotFoundException (line 21) | public FileNotFoundException(String detailMessage) {
method FileNotFoundException (line 25) | public FileNotFoundException(String detailMessage, Throwable throwable) {
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/exception/PageRenderingException.java
class PageRenderingException (line 3) | public class PageRenderingException extends Exception {
method PageRenderingException (line 6) | public PageRenderingException(int page, Throwable cause) {
method getPage (line 11) | public int getPage() {
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/link/DefaultLinkHandler.java
class DefaultLinkHandler (line 26) | public class DefaultLinkHandler implements LinkHandler {
method DefaultLinkHandler (line 32) | public DefaultLinkHandler(PDFView pdfView) {
method handleLinkEvent (line 36) | @Override
method handleUri (line 47) | private void handleUri(String uri) {
method handlePage (line 58) | private void handlePage(int page) {
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/link/LinkHandler.java
type LinkHandler (line 20) | public interface LinkHandler {
method handleLinkEvent (line 27) | void handleLinkEvent(LinkTapEvent event);
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/listener/Callbacks.java
class Callbacks (line 23) | public class Callbacks {
method setOnLoadComplete (line 77) | public void setOnLoadComplete(OnLoadCompleteListener onLoadCompleteLis...
method callOnLoadComplete (line 81) | public void callOnLoadComplete(int pagesCount) {
method setOnError (line 87) | public void setOnError(OnErrorListener onErrorListener) {
method getOnError (line 91) | public OnErrorListener getOnError() {
method setOnPageError (line 95) | public void setOnPageError(OnPageErrorListener onPageErrorListener) {
method callOnPageError (line 99) | public boolean callOnPageError(int page, Throwable error) {
method setOnRender (line 107) | public void setOnRender(OnRenderListener onRenderListener) {
method callOnRender (line 111) | public void callOnRender(int pagesCount) {
method setOnPageChange (line 117) | public void setOnPageChange(OnPageChangeListener onPageChangeListener) {
method callOnPageChange (line 121) | public void callOnPageChange(int page, int pagesCount) {
method setOnPageScroll (line 127) | public void setOnPageScroll(OnPageScrollListener onPageScrollListener) {
method callOnPageScroll (line 131) | public void callOnPageScroll(int currentPage, float offset) {
method setOnDraw (line 137) | public void setOnDraw(OnDrawListener onDrawListener) {
method getOnDraw (line 141) | public OnDrawListener getOnDraw() {
method setOnDrawAll (line 145) | public void setOnDrawAll(OnDrawListener onDrawAllListener) {
method getOnDrawAll (line 149) | public OnDrawListener getOnDrawAll() {
method setOnTap (line 153) | public void setOnTap(OnTapListener onTapListener) {
method callOnTap (line 157) | public boolean callOnTap(MotionEvent event) {
method setOnLongPress (line 161) | public void setOnLongPress(OnLongPressListener onLongPressListener) {
method callOnLongPress (line 165) | public void callOnLongPress(MotionEvent event) {
method setLinkHandler (line 171) | public void setLinkHandler(LinkHandler linkHandler) {
method callLinkHandler (line 175) | public void callLinkHandler(LinkTapEvent event) {
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/listener/OnDrawListener.java
type OnDrawListener (line 24) | public interface OnDrawListener {
method onLayerDrawn (line 37) | void onLayerDrawn(Canvas canvas, float pageWidth, float pageHeight, in...
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/listener/OnErrorListener.java
type OnErrorListener (line 18) | public interface OnErrorListener {
method onError (line 24) | void onError(Throwable t);
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/listener/OnLoadCompleteListener.java
type OnLoadCompleteListener (line 22) | public interface OnLoadCompleteListener {
method loadComplete (line 28) | void loadComplete(int nbPages);
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/listener/OnLongPressListener.java
type OnLongPressListener (line 24) | public interface OnLongPressListener {
method onLongPress (line 31) | void onLongPress(MotionEvent e);
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/listener/OnPageChangeListener.java
type OnPageChangeListener (line 22) | public interface OnPageChangeListener {
method onPageChanged (line 30) | void onPageChanged(int page, int pageCount);
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/listener/OnPageErrorListener.java
type OnPageErrorListener (line 18) | public interface OnPageErrorListener {
method onPageError (line 24) | void onPageError(int page, Throwable t);
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/listener/OnPageScrollListener.java
type OnPageScrollListener (line 22) | public interface OnPageScrollListener {
method onPageScrolled (line 30) | void onPageScrolled(int page, float positionOffset);
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/listener/OnRenderListener.java
type OnRenderListener (line 18) | public interface OnRenderListener {
method onInitiallyRendered (line 24) | void onInitiallyRendered(int nbPages);
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/listener/OnTapListener.java
type OnTapListener (line 24) | public interface OnTapListener {
method onTap (line 32) | boolean onTap(MotionEvent e);
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/model/LinkTapEvent.java
class LinkTapEvent (line 22) | public class LinkTapEvent {
method LinkTapEvent (line 30) | public LinkTapEvent(float originalX, float originalY, float documentX,...
method getOriginalX (line 39) | public float getOriginalX() {
method getOriginalY (line 43) | public float getOriginalY() {
method getDocumentX (line 47) | public float getDocumentX() {
method getDocumentY (line 51) | public float getDocumentY() {
method getMappedLinkRect (line 55) | public RectF getMappedLinkRect() {
method getLink (line 59) | public PdfDocument.Link getLink() {
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/model/PagePart.java
class PagePart (line 21) | public class PagePart {
method PagePart (line 33) | public PagePart(int page, Bitmap renderedBitmap, RectF pageRelativeBou...
method getCacheOrder (line 42) | public int getCacheOrder() {
method getPage (line 46) | public int getPage() {
method getRenderedBitmap (line 50) | public Bitmap getRenderedBitmap() {
method getPageRelativeBounds (line 54) | public RectF getPageRelativeBounds() {
method isThumbnail (line 58) | public boolean isThumbnail() {
method setCacheOrder (line 62) | public void setCacheOrder(int cacheOrder) {
method equals (line 66) | @Override
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/scroll/DefaultScrollHandle.java
class DefaultScrollHandle (line 18) | public class DefaultScrollHandle extends RelativeLayout implements Scrol...
method run (line 34) | @Override
method DefaultScrollHandle (line 40) | public DefaultScrollHandle(Context context) {
method DefaultScrollHandle (line 44) | public DefaultScrollHandle(Context context, boolean inverted) {
method setupLayout (line 54) | @Override
method destroyLayout (line 101) | @Override
method setScroll (line 106) | @Override
method setPosition (line 118) | private void setPosition(float pos) {
method calculateMiddle (line 146) | private void calculateMiddle() {
method hideDelayed (line 160) | @Override
method setPageNum (line 165) | @Override
method shown (line 173) | @Override
method show (line 178) | @Override
method hide (line 183) | @Override
method setTextColor (line 188) | public void setTextColor(int color) {
method setTextSize (line 195) | public void setTextSize(int size) {
method isPDFViewReady (line 199) | private boolean isPDFViewReady() {
method onTouchEvent (line 203) | @Override
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/scroll/ScrollHandle.java
type ScrollHandle (line 5) | public interface ScrollHandle {
method setScroll (line 12) | void setScroll(float position);
method setupLayout (line 21) | void setupLayout(PDFView pdfView);
method destroyLayout (line 27) | void destroyLayout();
method setPageNum (line 34) | void setPageNum(int pageNum);
method shown (line 41) | boolean shown();
method show (line 46) | void show();
method hide (line 51) | void hide();
method hideDelayed (line 56) | void hideDelayed();
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/source/AssetSource.java
class AssetSource (line 29) | public class AssetSource implements DocumentSource {
method AssetSource (line 33) | public AssetSource(String assetName) {
method createDocument (line 37) | @Override
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/source/ByteArraySource.java
class ByteArraySource (line 25) | public class ByteArraySource implements DocumentSource {
method ByteArraySource (line 29) | public ByteArraySource(byte[] data) {
method createDocument (line 33) | @Override
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/source/DocumentSource.java
type DocumentSource (line 25) | public interface DocumentSource {
method createDocument (line 26) | PdfDocument createDocument(Context context, PdfiumCore core, String pa...
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/source/FileSource.java
class FileSource (line 27) | public class FileSource implements DocumentSource {
method FileSource (line 31) | public FileSource(File file) {
method createDocument (line 35) | @Override
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/source/InputStreamSource.java
class InputStreamSource (line 27) | public class InputStreamSource implements DocumentSource {
method InputStreamSource (line 31) | public InputStreamSource(InputStream inputStream) {
method createDocument (line 35) | @Override
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/source/UriSource.java
class UriSource (line 27) | public class UriSource implements DocumentSource {
method UriSource (line 31) | public UriSource(Uri uri) {
method createDocument (line 35) | @Override
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/util/ArrayUtils.java
class ArrayUtils (line 21) | public class ArrayUtils {
method ArrayUtils (line 23) | private ArrayUtils() {
method deleteDuplicatedPages (line 28) | public static int[] deleteDuplicatedPages(int[] pages) {
method calculateIndexesInDuplicateArray (line 45) | public static int[] calculateIndexesInDuplicateArray(int[] originalUse...
method arrayToString (line 63) | public static String arrayToString(int[] array) {
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/util/Constants.java
class Constants (line 18) | public class Constants {
class Cache (line 35) | public static class Cache {
class Pinch (line 43) | public static class Pinch {
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/util/FileUtils.java
class FileUtils (line 26) | public class FileUtils {
method FileUtils (line 28) | private FileUtils() {
method fileFromAsset (line 32) | public static File fileFromAsset(Context context, String assetName) th...
method copy (line 41) | public static void copy(InputStream inputStream, File output) throws I...
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/util/FitPolicy.java
type FitPolicy (line 18) | public enum FitPolicy {
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/util/MathUtils.java
class MathUtils (line 18) | public class MathUtils {
method MathUtils (line 24) | private MathUtils() {
method limit (line 35) | public static int limit(int number, int between, int and) {
method limit (line 52) | public static float limit(float number, float between, float and) {
method max (line 62) | public static float max(float number, float max) {
method min (line 69) | public static float min(float number, float min) {
method max (line 76) | public static int max(int number, int max) {
method min (line 83) | public static int min(int number, int min) {
method floor (line 96) | static public int floor(float value) {
method ceil (line 102) | static public int ceil(float value) {
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/util/PageSizeCalculator.java
class PageSizeCalculator (line 21) | public class PageSizeCalculator {
method PageSizeCalculator (line 33) | public PageSizeCalculator(FitPolicy fitPolicy, Size originalMaxWidthPa...
method calculate (line 43) | public SizeF calculate(Size pageSize) {
method getOptimalMaxWidthPageSize (line 59) | public SizeF getOptimalMaxWidthPageSize() {
method getOptimalMaxHeightPageSize (line 63) | public SizeF getOptimalMaxHeightPageSize() {
method calculateMaxPages (line 67) | private void calculateMaxPages() {
method fitWidth (line 91) | private SizeF fitWidth(Size pageSize, float maxWidth) {
method fitHeight (line 99) | private SizeF fitHeight(Size pageSize, float maxHeight) {
method fitBoth (line 107) | private SizeF fitBoth(Size pageSize, float maxWidth, float maxHeight) {
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/util/SnapEdge.java
type SnapEdge (line 18) | public enum SnapEdge {
FILE: android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/util/Util.java
class Util (line 25) | public class Util {
method getDP (line 28) | public static int getDP(Context context, int dp) {
method toByteArray (line 32) | public static byte[] toByteArray(InputStream inputStream) throws IOExc...
FILE: sample/src/main/java/com/github/barteksc/sample/PDFViewActivity.java
class PDFViewActivity (line 30) | public class PDFViewActivity extends AppCompatActivity implements
method onCreate (line 52) | @Override
method pickFile (line 67) | private void pickFile() {
method launchPicker (line 76) | private void launchPicker() {
method displayFromAsset (line 86) | private void displayFromAsset(String assetFileName) {
method displayFromUri (line 100) | private void displayFromUri(Uri uri) {
method getFileName (line 113) | private String getFileName(Uri uri) {
method onPageChanged (line 129) | @Override
method loadComplete (line 135) | @Override
method printBookmarksTree (line 150) | private void printBookmarksTree(List<PdfDocument.Bookmark> tree, Strin...
method onRequestPermissionsResult (line 159) | @Override
method onPageError (line 169) | @Override
Condensed preview — 67 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (244K chars).
[
{
"path": ".gitignore",
"chars": 274,
"preview": "target/\nbuild/\nlint.xml\nbin/\ngen/\n.settings\n.project\n.classpath\nout\ngen-external-apklibs/\nclasses/\n\n# Local configuratio"
},
{
"path": "16KB_SUPPORT.md",
"chars": 4547,
"preview": "# 16 KB Page Size Support\n\nThis Android PDF Viewer library has been updated to support 16 KB page sizes, which is requir"
},
{
"path": "CHANGELOG.md",
"chars": 8591,
"preview": "## 3.2.0-beta.1 (2019-08-18)\n* Merge PR #714 with optimized page load\n* Merge PR #776 with fix for max & min zoom level\n"
},
{
"path": "LICENSE",
"chars": 11357,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "README.md",
"chars": 12329,
"preview": "\n# Change of ownership and looking for contributors!\n\nThe ownership of the project was recently changed and we are activ"
},
{
"path": "android-pdf-viewer/bintray.gradle",
"chars": 2147,
"preview": "apply plugin: 'com.github.dcendents.android-maven'\napply plugin: 'com.jfrog.bintray'\n\ngroup = publishedGroupId\nversion ="
},
{
"path": "android-pdf-viewer/build.gradle",
"chars": 1811,
"preview": "apply plugin: 'com.android.library'\n\next {\n bintrayRepo = 'maven'\n bintrayName = 'android-pdf-viewer'\n\n publish"
},
{
"path": "android-pdf-viewer/src/main/AndroidManifest.xml",
"chars": 135,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n "
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/AnimationManager.java",
"chars": 7036,
"preview": "/**\r\n * Copyright 2016 Bartosz Schiller\r\n * <p/>\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n *"
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/CacheManager.java",
"chars": 6138,
"preview": "/**\r\n * Copyright 2016 Bartosz Schiller\r\n * <p/>\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n *"
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/DecodingAsyncTask.java",
"chars": 2915,
"preview": "/**\n * Copyright 2016 Bartosz Schiller\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you"
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/DragPinchManager.java",
"chars": 11571,
"preview": "/**\r\n * Copyright 2016 Bartosz Schiller\r\n * <p/>\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n *"
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/PDFView.java",
"chars": 51853,
"preview": "/**\r\n * Copyright 2016 Bartosz Schiller\r\n * <p/>\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n *"
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/PagesLoader.java",
"chars": 12754,
"preview": "/**\n * Copyright 2017 Bartosz Schiller\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you"
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/PdfFile.java",
"chars": 13035,
"preview": "/**\n * Copyright 2017 Bartosz Schiller\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you"
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/RenderingHandler.java",
"chars": 5505,
"preview": "/**\r\n * Copyright 2016 Bartosz Schiller\r\n * <p/>\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n *"
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/exception/FileNotFoundException.java",
"chars": 955,
"preview": "/**\n * Copyright 2016 Bartosz Schiller\n * <p>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you "
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/exception/PageRenderingException.java",
"chars": 309,
"preview": "package com.github.barteksc.pdfviewer.exception;\n\npublic class PageRenderingException extends Exception {\n private fi"
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/link/DefaultLinkHandler.java",
"chars": 1945,
"preview": "/**\n * Copyright 2017 Bartosz Schiller\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you"
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/link/LinkHandler.java",
"chars": 895,
"preview": "/**\n * Copyright 2017 Bartosz Schiller\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you"
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/listener/Callbacks.java",
"chars": 5206,
"preview": "/**\n * Copyright 2017 Bartosz Schiller\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you"
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/listener/OnDrawListener.java",
"chars": 1348,
"preview": "/**\r\n * Copyright 2016 Bartosz Schiller\r\n * <p>\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n * "
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/listener/OnErrorListener.java",
"chars": 830,
"preview": "/**\n * Copyright 2016 Bartosz Schiller\n * <p>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you "
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/listener/OnLoadCompleteListener.java",
"chars": 976,
"preview": "/**\r\n * Copyright 2016 Bartosz Schiller\r\n * <p>\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n * "
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/listener/OnLongPressListener.java",
"chars": 1059,
"preview": "/**\n * Copyright 2017 Bartosz Schiller\n * <p>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you "
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/listener/OnPageChangeListener.java",
"chars": 1077,
"preview": "/**\r\n * Copyright 2016 Bartosz Schiller\r\n * <p>\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n * "
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/listener/OnPageErrorListener.java",
"chars": 853,
"preview": "/**\n * Copyright 2017 Bartosz Schiller\n * <p>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you "
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/listener/OnPageScrollListener.java",
"chars": 1063,
"preview": "/**\n * Copyright 2016 Bartosz Schiller\n * <p>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you "
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/listener/OnRenderListener.java",
"chars": 845,
"preview": "/**\n * Copyright 2017 Bartosz Schiller\n * <p>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you "
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/listener/OnTapListener.java",
"chars": 1121,
"preview": "/**\n * Copyright 2017 Bartosz Schiller\n * <p>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you "
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/model/LinkTapEvent.java",
"chars": 1719,
"preview": "/**\n * Copyright 2016 Bartosz Schiller\n * <p>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you "
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/model/PagePart.java",
"chars": 2314,
"preview": "/**\r\n * Copyright 2016 Bartosz Schiller\r\n * <p>\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n * "
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/scroll/DefaultScrollHandle.java",
"chars": 7448,
"preview": "package com.github.barteksc.pdfviewer.scroll;\n\nimport android.content.Context;\nimport android.graphics.Color;\nimport and"
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/scroll/ScrollHandle.java",
"chars": 1216,
"preview": "package com.github.barteksc.pdfviewer.scroll;\n\nimport com.github.barteksc.pdfviewer.PDFView;\n\npublic interface ScrollHan"
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/source/AssetSource.java",
"chars": 1428,
"preview": "/*\n * Copyright (C) 2016 Bartosz Schiller.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you "
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/source/ByteArraySource.java",
"chars": 1132,
"preview": "/*\n * Copyright (C) 2016 Bartosz Schiller.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you "
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/source/DocumentSource.java",
"chars": 930,
"preview": "/*\n * Copyright (C) 2016 Bartosz Schiller.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you "
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/source/FileSource.java",
"chars": 1283,
"preview": "/*\n * Copyright (C) 2016 Bartosz Schiller.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you "
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/source/InputStreamSource.java",
"chars": 1275,
"preview": "/*\n * Copyright (C) 2016 Bartosz Schiller.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you "
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/source/UriSource.java",
"chars": 1267,
"preview": "/*\n * Copyright (C) 2016 Bartosz Schiller.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you "
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/util/ArrayUtils.java",
"chars": 2389,
"preview": "/**\r\n * Copyright 2016 Bartosz Schiller\r\n * <p>\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n * "
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/util/Constants.java",
"chars": 1689,
"preview": "/**\r\n * Copyright 2016 Bartosz Schiller\r\n * <p/>\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n *"
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/util/FileUtils.java",
"chars": 1982,
"preview": "/**\n * Copyright 2016 Bartosz Schiller\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you"
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/util/FitPolicy.java",
"chars": 707,
"preview": "/**\n * Copyright 2017 Bartosz Schiller\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you"
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/util/MathUtils.java",
"chars": 3313,
"preview": "/**\r\n * Copyright 2016 Bartosz Schiller\r\n * <p/>\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n *"
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/util/PageSizeCalculator.java",
"chars": 5029,
"preview": "/**\n * Copyright 2017 Bartosz Schiller\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you"
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/util/SnapEdge.java",
"chars": 711,
"preview": "/**\n * Copyright 2017 Bartosz Schiller\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you"
},
{
"path": "android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/util/Util.java",
"chars": 1434,
"preview": "/*\n * Copyright (C) 2016 Bartosz Schiller.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you "
},
{
"path": "android-pdf-viewer/src/main/res/drawable/default_scroll_handle_bottom.xml",
"chars": 352,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape\n xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android"
},
{
"path": "android-pdf-viewer/src/main/res/drawable/default_scroll_handle_left.xml",
"chars": 254,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<rotate xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:dr"
},
{
"path": "android-pdf-viewer/src/main/res/drawable/default_scroll_handle_right.xml",
"chars": 354,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape\n xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android"
},
{
"path": "android-pdf-viewer/src/main/res/drawable/default_scroll_handle_top.xml",
"chars": 255,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<rotate xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:dr"
},
{
"path": "android-pdf-viewer/src/main/res/values/attrs.xml",
"chars": 397,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <declare-styleable name=\"ScrollBar\">\n <attr name=\"sb_handl"
},
{
"path": "build.gradle",
"chars": 540,
"preview": "\nbuildscript {\n repositories {\n google()\n mavenCentral()\n }\n dependencies {\n classpath 'co"
},
{
"path": "gradle/wrapper/gradle-wrapper.properties",
"chars": 231,
"preview": "#Wed Sep 10 21:17:12 IST 2025\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://"
},
{
"path": "gradle.properties",
"chars": 161,
"preview": "org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8\nandroid.useAndroidX=true\nandroid.enableJetifier=true\n\n# 16 KB page si"
},
{
"path": "gradlew",
"chars": 5080,
"preview": "#!/usr/bin/env bash\n\n##############################################################################\n##\n## Gradle start "
},
{
"path": "gradlew.bat",
"chars": 3089,
"preview": "@REM\n@REM Copyright 2014 Joan Zapata\n@REM\n@REM This file is part of Android-pdfview.\n@REM\n@REM Android-pdfview is free s"
},
{
"path": "sample/build.gradle",
"chars": 1228,
"preview": "buildscript {\n repositories {\n google()\n mavenCentral()\n }\n}\n\nrepositories {\n google()\n mavenC"
},
{
"path": "sample/src/main/AndroidManifest.xml",
"chars": 603,
"preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n <uses-permission android:name=\"android.permis"
},
{
"path": "sample/src/main/java/com/github/barteksc/sample/PDFViewActivity.java",
"chars": 6404,
"preview": "package com.github.barteksc.sample;\n\nimport android.content.ActivityNotFoundException;\nimport android.content.Intent;\nim"
},
{
"path": "sample/src/main/res/layout/activity_main.xml",
"chars": 387,
"preview": "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\txmlns:tools=\"http://schemas.android.com/tool"
},
{
"path": "sample/src/main/res/menu/options.xml",
"chars": 358,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app=\"h"
},
{
"path": "sample/src/main/res/values/strings.xml",
"chars": 232,
"preview": "<resources>\n <string name=\"app_name\">AndroidPdfViewer demo</string>\n <string name=\"pick_file\">Pick file</string>\n "
},
{
"path": "sample/src/main/res/values/styles.xml",
"chars": 26,
"preview": "<resources>\n\n\n</resources>"
},
{
"path": "settings.gradle",
"chars": 47,
"preview": "include ':android-pdf-viewer'\ninclude ':sample'"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the DImuthuUpe/AndroidPdfViewer GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 67 files (222.4 KB), approximately 53.3k tokens, and a symbol index with 424 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.