Skip to content

Commit c242b4d

Browse files
committed
Added functionality to Disable cache
1 parent d8537fb commit c242b4d

File tree

7 files changed

+113
-53
lines changed

7 files changed

+113
-53
lines changed

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,15 @@ binding.pdfView.statusListener = object : PdfRendererView.StatusCallBack {
206206
override fun onPageChanged(currentPage: Int, totalPage: Int) {
207207
Log.i("PDF Status", "Page changed: $currentPage / $totalPage")
208208
}
209+
210+
override fun onPdfRenderStart() {
211+
Log.i("PDF Status", "Render started")
212+
}
213+
214+
override fun onPdfRenderSuccess() {
215+
Log.i("PDF Status", "Render successful")
216+
binding.pdfView.jumpToPage($number) // Recommend to use `jumpToPage` inside `onPdfRenderSuccess`
217+
}
209218
}
210219
```
211220

pdfViewer/src/main/java/com/rajat/pdfviewer/PdfDownloader.kt

Lines changed: 65 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,20 @@ import android.content.Context
44
import android.os.Handler
55
import android.os.Looper
66
import android.util.Log
7-
import com.rajat.pdfviewer.util.CacheHelper
7+
import com.rajat.pdfviewer.util.CacheManager
88
import com.rajat.pdfviewer.util.CacheStrategy
9-
import com.rajat.pdfviewer.util.CommonUtils.Companion.MAX_CACHED_PDFS
109
import com.rajat.pdfviewer.util.FileUtils.getCachedFileName
1110
import com.rajat.pdfviewer.util.FileUtils.isValidPdf
1211
import com.rajat.pdfviewer.util.FileUtils.writeFile
13-
import kotlinx.coroutines.*
14-
import okhttp3.*
12+
import kotlinx.coroutines.CoroutineScope
13+
import kotlinx.coroutines.Dispatchers
14+
import kotlinx.coroutines.delay
15+
import kotlinx.coroutines.launch
16+
import kotlinx.coroutines.withContext
17+
import okhttp3.OkHttpClient
18+
import okhttp3.Protocol
19+
import okhttp3.Request
20+
import okhttp3.Response
1521
import java.io.File
1622
import java.io.IOException
1723

@@ -52,16 +58,19 @@ class PdfDownloader(
5258

5359
private suspend fun checkAndDownload(downloadUrl: String) {
5460
val cachedFileName = getCachedFileName(downloadUrl)
55-
val cacheDir = File(listener.getContext().cacheDir, "___pdf___cache___/$cachedFileName")
56-
if (!cacheDir.exists()) {
57-
cacheDir.mkdirs()
61+
62+
if (cacheStrategy != CacheStrategy.DISABLE_CACHE){
63+
CacheManager.clearCacheDir(listener.getContext())
5864
}
5965

60-
val pdfFile = File(cacheDir, cachedFileName)
66+
val cacheDir = File(
67+
listener.getContext().cacheDir,
68+
"___pdf___cache___/$cachedFileName"
69+
).apply { mkdirs() }
6170

62-
CacheHelper.handleCacheStrategy(TAG, cacheDir, cacheStrategy, cachedFileName, MAX_CACHED_PDFS)
71+
val pdfFile = File(cacheDir, cachedFileName)
6372

64-
if (pdfFile.exists() && isValidPdf(pdfFile)) {
73+
if (cacheStrategy != CacheStrategy.DISABLE_CACHE && pdfFile.exists() && isValidPdf(pdfFile)) {
6574
withContext(Dispatchers.Main) {
6675
listener.onDownloadSuccess(pdfFile)
6776
}
@@ -95,7 +104,12 @@ class PdfDownloader(
95104
delay(RETRY_DELAY)
96105
} else {
97106
withContext(Dispatchers.Main) {
98-
listener.onDownloadError(DownloadFailedException("Failed after $MAX_RETRIES attempts", e))
107+
listener.onDownloadError(
108+
DownloadFailedException(
109+
"Failed after $MAX_RETRIES attempts",
110+
e
111+
)
112+
)
99113
}
100114
}
101115
}
@@ -108,48 +122,49 @@ class PdfDownloader(
108122
message.contains("Downloaded file is not a valid PDF", ignoreCase = true)
109123
}
110124

111-
private suspend fun downloadFile(downloadUrl: String, pdfFile: File) = withContext(Dispatchers.IO) {
112-
val tempFile = File.createTempFile("download_", ".tmp", pdfFile.parentFile)
125+
private suspend fun downloadFile(downloadUrl: String, pdfFile: File) =
126+
withContext(Dispatchers.IO) {
127+
val tempFile = File.createTempFile("download_", ".tmp", pdfFile.parentFile)
113128

114-
try {
115-
if (pdfFile.exists() && !isValidPdf(pdfFile)) {
116-
pdfFile.delete()
117-
}
129+
try {
130+
if (pdfFile.exists() && !isValidPdf(pdfFile)) {
131+
pdfFile.delete()
132+
}
118133

119-
val response = makeNetworkRequest(downloadUrl)
120-
validateResponse(response)
134+
val response = makeNetworkRequest(downloadUrl)
135+
validateResponse(response)
121136

122-
response.body?.use { body ->
123-
body.byteStream().use { inputStream ->
124-
writeFile(inputStream, tempFile, body.contentLength()) { progress ->
125-
Handler(Looper.getMainLooper()).post {
126-
listener.onDownloadProgress(progress, body.contentLength())
137+
response.body?.use { body ->
138+
body.byteStream().use { inputStream ->
139+
writeFile(inputStream, tempFile, body.contentLength()) { progress ->
140+
Handler(Looper.getMainLooper()).post {
141+
listener.onDownloadProgress(progress, body.contentLength())
142+
}
127143
}
128144
}
129-
}
130-
} ?: throw IOException("Empty response body received for PDF")
145+
} ?: throw IOException("Empty response body received for PDF")
131146

132-
val renamed = tempFile.renameTo(pdfFile)
133-
if (!renamed) {
134-
tempFile.delete()
135-
throw IOException("Failed to rename temp file to final PDF path")
136-
}
147+
val renamed = tempFile.renameTo(pdfFile)
148+
if (!renamed) {
149+
tempFile.delete()
150+
throw IOException("Failed to rename temp file to final PDF path")
151+
}
137152

138-
if (!isValidPdf(pdfFile)) {
139-
pdfFile.delete()
140-
throw InvalidPdfException("Downloaded file is not a valid PDF")
141-
}
153+
if (!isValidPdf(pdfFile)) {
154+
pdfFile.delete()
155+
throw InvalidPdfException("Downloaded file is not a valid PDF")
156+
}
142157

143-
Log.d(TAG, "Downloaded PDF to: ${pdfFile.absolutePath}")
158+
Log.d(TAG, "Downloaded PDF to: ${pdfFile.absolutePath}")
144159

145-
withContext(Dispatchers.Main) {
146-
listener.onDownloadSuccess(pdfFile)
160+
withContext(Dispatchers.Main) {
161+
listener.onDownloadSuccess(pdfFile)
162+
}
163+
} catch (e: Exception) {
164+
tempFile.delete()
165+
throw e
147166
}
148-
} catch (e: Exception) {
149-
tempFile.delete()
150-
throw e
151167
}
152-
}
153168

154169
private fun makeNetworkRequest(downloadUrl: String): Response {
155170
val requestBuilder = Request.Builder().url(downloadUrl)
@@ -164,11 +179,17 @@ class PdfDownloader(
164179
}
165180

166181
val contentType = response.header("Content-Type", "")
167-
if (!contentType.isNullOrEmpty() && !contentType.contains("application/pdf", ignoreCase = true)) {
182+
if (!contentType.isNullOrEmpty() && !contentType.contains(
183+
"application/pdf",
184+
ignoreCase = true
185+
)
186+
) {
168187
throw InvalidPdfException("Invalid content type received: $contentType. Expected a PDF file.")
169188
}
170189
}
171190
}
172191

173-
class DownloadFailedException(message: String, cause: Throwable? = null) : IOException(message, cause)
192+
class DownloadFailedException(message: String, cause: Throwable? = null) :
193+
IOException(message, cause)
194+
174195
class InvalidPdfException(message: String) : IOException(message)

pdfViewer/src/main/java/com/rajat/pdfviewer/PdfRendererView.kt

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,12 @@ import android.graphics.drawable.Drawable
99
import android.net.Uri
1010
import android.os.Build
1111
import android.os.Bundle
12-
import android.os.Handler
13-
import android.os.Looper
1412
import android.os.Parcelable
1513
import android.util.AttributeSet
1614
import android.view.LayoutInflater
1715
import android.view.WindowManager
1816
import android.widget.FrameLayout
1917
import android.widget.TextView
20-
import androidx.core.view.isVisible
2118
import androidx.lifecycle.Lifecycle
2219
import androidx.lifecycle.LifecycleCoroutineScope
2320
import androidx.lifecycle.LifecycleObserver
@@ -26,6 +23,7 @@ import androidx.recyclerview.widget.DividerItemDecoration
2623
import androidx.recyclerview.widget.LinearLayoutManager
2724
import androidx.recyclerview.widget.RecyclerView
2825
import androidx.recyclerview.widget.RecyclerView.NO_POSITION
26+
import com.rajat.pdfviewer.util.CacheManager
2927
import com.rajat.pdfviewer.util.CacheStrategy
3028
import kotlinx.coroutines.CoroutineScope
3129
import kotlinx.coroutines.Dispatchers
@@ -34,7 +32,6 @@ import kotlinx.coroutines.launch
3432
import kotlinx.coroutines.withContext
3533
import org.jetbrains.annotations.TestOnly
3634
import java.io.File
37-
import java.io.FileNotFoundException
3835

3936
/**
4037
* Created by Rajat on 11,July,2020
@@ -89,6 +86,14 @@ class PdfRendererView @JvmOverloads constructor(
8986
get() {
9087
return pdfRendererCore.getPageCount()
9188
}
89+
90+
/**
91+
* Clears the cache directory of the application.
92+
* @param context The application context.
93+
*/
94+
suspend fun PdfRendererView.clearCache(context: Context) {
95+
CacheManager.clearCacheDir(context)
96+
}
9297
//endregion
9398

9499
init {
@@ -473,5 +478,4 @@ class PdfRendererView @JvmOverloads constructor(
473478
interface ZoomListener {
474479
fun onZoomChanged(isZoomedIn: Boolean, scale: Float)
475480
}
476-
477481
}

pdfViewer/src/main/java/com/rajat/pdfviewer/util/CacheHelper.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import android.util.Log
44
import kotlinx.coroutines.Dispatchers
55
import kotlinx.coroutines.withContext
66
import java.io.File
7+
import java.security.MessageDigest
78
import kotlin.math.max
89

910
object CacheHelper {
@@ -28,6 +29,9 @@ object CacheHelper {
2829
updateCacheAccessTime(cacheDir)
2930
enforceCacheLimit(origin, cacheDir, maxCachedPdfs)
3031
}
32+
CacheStrategy.DISABLE_CACHE -> {
33+
// no-op
34+
}
3135
}
3236
}
3337

@@ -66,4 +70,15 @@ object CacheHelper {
6670
private fun updateCacheAccessTime(cacheDir: File) {
6771
cacheDir.setLastModified(System.currentTimeMillis())
6872
}
73+
74+
fun getCacheKey(source: String): String {
75+
val prefix = if (source.startsWith("http")) "url_" else "file_"
76+
val hash = sha256(source)
77+
return prefix + hash
78+
}
79+
80+
private fun sha256(input: String): String {
81+
val bytes = MessageDigest.getInstance("SHA-256").digest(input.toByteArray())
82+
return bytes.joinToString("") { "%02x".format(it) }
83+
}
6984
}

pdfViewer/src/main/java/com/rajat/pdfviewer/util/CacheManager.kt

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ class CacheManager(
2222
private var cacheDir = File(context.cacheDir, "${CACHE_PATH}/$currentOpenedFileName")
2323

2424
suspend fun initialize() = withContext(Dispatchers.IO) {
25+
if (cacheStrategy == CacheStrategy.DISABLE_CACHE) return@withContext
26+
2527
cacheDir = File(context.cacheDir, "$CACHE_PATH/$currentOpenedFileName")
2628
if (!cacheDir.exists()) {
2729
cacheDir.mkdirs()
@@ -45,7 +47,10 @@ class CacheManager(
4547
}
4648

4749
suspend fun getBitmapFromCache(pageNo: Int): Bitmap? = withContext(Dispatchers.IO) {
48-
memoryCache.get(pageNo) ?: decodeBitmapFromDiskCache(pageNo)?.also {
50+
memoryCache.get(pageNo)?.let { return@withContext it }
51+
if (cacheStrategy == CacheStrategy.DISABLE_CACHE) return@withContext null
52+
53+
decodeBitmapFromDiskCache(pageNo)?.also {
4954
memoryCache.put(pageNo, it)
5055
}
5156
}
@@ -57,11 +62,15 @@ class CacheManager(
5762

5863
suspend fun addBitmapToCache(pageNo: Int, bitmap: Bitmap) {
5964
memoryCache.put(pageNo, bitmap)
60-
writeBitmapToCache(pageNo, bitmap)
65+
if (cacheStrategy != CacheStrategy.DISABLE_CACHE) {
66+
writeBitmapToCache(pageNo, bitmap)
67+
}
6168
}
6269

6370
private suspend fun writeBitmapToCache(pageNo: Int, bitmap: Bitmap) = withContext(Dispatchers.IO) {
71+
6472
runCatching {
73+
6574
cacheDir.mkdirs()
6675
val savePath = File(cacheDir, cachedFileNameWithFormat(pageNo))
6776
savePath.parentFile?.mkdirs()
@@ -74,6 +83,7 @@ class CacheManager(
7483
}
7584

7685
suspend fun pageExistsInCache(pageNo: Int): Boolean = withContext(Dispatchers.IO) {
86+
if (cacheStrategy == CacheStrategy.DISABLE_CACHE) return@withContext false
7787
File(cacheDir, cachedFileNameWithFormat(pageNo)).exists()
7888
}
7989

pdfViewer/src/main/java/com/rajat/pdfviewer/util/Enums.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@ enum class saveTo {
1414

1515
enum class CacheStrategy {
1616
MINIMIZE_CACHE, // Keep only one file at a time
17-
MAXIMIZE_PERFORMANCE // Store up to 5 PDFs using LRU eviction
17+
MAXIMIZE_PERFORMANCE, // Store up to 5 PDFs using LRU eviction
18+
DISABLE_CACHE // Disable caching
1819
}

pdfViewer/src/main/java/com/rajat/pdfviewer/util/FileUtils.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ object FileUtils {
6464

6565

6666
fun getCachedFileName(url: String): String {
67-
return url.hashCode().toString() + ".pdf"
67+
return CacheHelper.getCacheKey(url) + ".pdf"
6868
}
6969

7070
fun clearPdfCache(context: Context, exceptFileName: String? = null) {

0 commit comments

Comments
 (0)