Merge remote-tracking branch 'origin/Issue#2868' into Issue#2868

This commit is contained in:
MohitMaliFtechiz 2022-06-23 11:08:57 +05:30
commit c780e1a67d
4 changed files with 112 additions and 37 deletions

View File

@ -18,8 +18,10 @@
package org.kiwix.kiwixmobile.core.main; package org.kiwix.kiwixmobile.core.main;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Build;
import android.util.Log; import android.util.Log;
import android.webkit.MimeTypeMap; import android.webkit.MimeTypeMap;
import android.webkit.WebResourceRequest; import android.webkit.WebResourceRequest;
@ -27,9 +29,12 @@ import android.webkit.WebResourceResponse;
import android.webkit.WebView; import android.webkit.WebView;
import android.webkit.WebViewClient; import android.webkit.WebViewClient;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.core.content.FileProvider;
import java.io.File;
import java.util.HashMap; import java.util.HashMap;
import org.kiwix.kiwixmobile.core.CoreApp; import org.kiwix.kiwixmobile.core.CoreApp;
import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer; import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer;
import org.kiwix.kiwixmobile.core.utils.files.FileUtils;
import static org.kiwix.kiwixmobile.core.reader.ZimFileReader.CONTENT_PREFIX; import static org.kiwix.kiwixmobile.core.reader.ZimFileReader.CONTENT_PREFIX;
import static org.kiwix.kiwixmobile.core.reader.ZimFileReader.UI_URI; import static org.kiwix.kiwixmobile.core.reader.ZimFileReader.UI_URI;
@ -97,11 +102,22 @@ public class CoreWebViewClient extends WebViewClient {
private boolean handleEpubAndPdf(String url) { private boolean handleEpubAndPdf(String url) {
String extension = MimeTypeMap.getFileExtensionFromUrl(url); String extension = MimeTypeMap.getFileExtensionFromUrl(url);
if (DOCUMENT_TYPES.containsKey(extension)) { if (DOCUMENT_TYPES.containsKey(extension)) {
Intent intent = new Intent(Intent.ACTION_VIEW); File savedFile = FileUtils.downloadFileFromUrl(url, null, zimReaderContainer);
Uri uri = Uri.parse(url); if (savedFile != null && savedFile.exists()) {
intent.setDataAndType(uri, DOCUMENT_TYPES.get(extension)); Context context = CoreApp.getInstance();
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); Uri uri = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
callback.openExternalUrl(intent); ? FileProvider.getUriForFile(
context,
context.getPackageName() + ".fileprovider", savedFile)
: Uri.fromFile(savedFile);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri, DOCUMENT_TYPES.get(extension));
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
callback.openExternalUrl(intent);
}
return true; return true;
} }
return false; return false;

View File

@ -20,12 +20,9 @@ package org.kiwix.kiwixmobile.core.main
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.net.Uri
import android.os.Environment
import android.os.Handler import android.os.Handler
import android.os.Message import android.os.Message
import android.util.AttributeSet import android.util.AttributeSet
import android.util.Log
import android.view.ContextMenu import android.view.ContextMenu
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -40,8 +37,7 @@ import org.kiwix.kiwixmobile.core.extensions.toast
import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer
import org.kiwix.kiwixmobile.core.utils.LanguageUtils.Companion.getCurrentLocale import org.kiwix.kiwixmobile.core.utils.LanguageUtils.Companion.getCurrentLocale
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
import java.io.File import org.kiwix.kiwixmobile.core.utils.files.FileUtils
import java.io.IOException
import javax.inject.Inject import javax.inject.Inject
private const val INITIAL_SCALE = 100 private const val INITIAL_SCALE = 100
@ -147,39 +143,16 @@ open class KiwixWebView @SuppressLint("SetJavaScriptEnabled") constructor(
internal class SaveHandler(private val zimReaderContainer: ZimReaderContainer) : internal class SaveHandler(private val zimReaderContainer: ZimReaderContainer) :
Handler() { Handler() {
private fun getDecodedFileName(url: String?, src: String?): String =
url?.substringAfterLast("/", "")
?.takeIf { it.contains(".") }
?: src?.substringAfterLast("/", "")
?.substringAfterLast("%3A") ?: ""
@SuppressWarnings("NestedBlockDepth") @SuppressWarnings("NestedBlockDepth")
override fun handleMessage(msg: Message) { override fun handleMessage(msg: Message) {
val url = msg.data["url"] as? String val url = msg.data["url"] as? String
val src = msg.data["src"] as? String val src = msg.data["src"] as? String
if (url != null || src != null) { if (url != null || src != null) {
val fileName = getDecodedFileName(url, src) val savedFile = FileUtils.downloadFileFromUrl(url, src, zimReaderContainer)
var root = savedFile?.let {
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) instance.toast(instance.getString(R.string.save_media_saved, it.name))
if (instance.externalMediaDirs.isNotEmpty()) { } ?: run {
root = instance.externalMediaDirs[0]
}
val fileToSave = sequence {
yield(File(root, fileName))
yieldAll(
generateSequence(1) { it + 1 }.map {
File(root, fileName.replace(".", "_$it."))
}
)
}.first { !it.exists() }
val source = Uri.parse(src)
try {
zimReaderContainer.load("$source", emptyMap()).data.use { inputStream ->
fileToSave.outputStream().use { inputStream.copyTo(it) }
}
instance.toast(instance.getString(R.string.save_media_saved, fileToSave.name))
} catch (e: IOException) {
Log.w("kiwix", "Couldn't save image", e)
instance.toast(R.string.save_media_error) instance.toast(R.string.save_media_error)
} }
} }

View File

@ -28,11 +28,13 @@ import android.provider.DocumentsContract
import android.util.Log import android.util.Log
import android.widget.Toast import android.widget.Toast
import androidx.documentfile.provider.DocumentFile import androidx.documentfile.provider.DocumentFile
import org.kiwix.kiwixmobile.core.CoreApp
import org.kiwix.kiwixmobile.core.R import org.kiwix.kiwixmobile.core.R
import org.kiwix.kiwixmobile.core.downloader.ChunkUtils import org.kiwix.kiwixmobile.core.downloader.ChunkUtils
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity.Book import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity.Book
import org.kiwix.kiwixmobile.core.extensions.get import org.kiwix.kiwixmobile.core.extensions.get
import org.kiwix.kiwixmobile.core.extensions.toast import org.kiwix.kiwixmobile.core.extensions.toast
import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer
import java.io.BufferedReader import java.io.BufferedReader
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
@ -288,4 +290,48 @@ object FileUtils {
} }
return null return null
} }
/**
* Returns the file name from the url or src. In url it gets the file name from the last '/' and
* if it contains '.'. If the url is null then it'll get the file name from the last '/'.
* If the url and src doesn't exist it returns the empty string.
*/
fun getDecodedFileName(url: String?, src: String?): String =
url?.substringAfterLast("/", "")
?.takeIf { it.contains(".") }
?: src?.substringAfterLast("/", "")
?.substringAfterLast("%3A") ?: ""
@JvmStatic fun downloadFileFromUrl(
url: String?,
src: String?,
zimReaderContainer: ZimReaderContainer
): File? {
val fileName = getDecodedFileName(url, src)
var root =
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
if (CoreApp.instance.externalMediaDirs.isNotEmpty()) {
root = CoreApp.instance.externalMediaDirs[0]
}
val fileToSave = sequence {
yield(File(root, fileName))
yieldAll(
generateSequence(1) { it + 1 }.map {
File(
root, fileName.replace(".", "_$it.")
)
}
)
}.first { !it.exists() }
val source = if (url == null) Uri.parse(src) else Uri.parse(url)
return try {
zimReaderContainer.load("$source", emptyMap()).data.use { inputStream ->
fileToSave.outputStream().use { inputStream.copyTo(it) }
}
fileToSave
} catch (e: IOException) {
Log.w("kiwix", "Couldn't save file", e)
null
}
}
} }

View File

@ -88,4 +88,44 @@ class FileUtilsTest {
every { mockFile.path } returns "$fileName$extension" every { mockFile.path } returns "$fileName$extension"
every { mockFile.exists() } returns fileExists every { mockFile.exists() } returns fileExists
} }
@Test
fun `test decode file name`() {
val fileName =
FileUtils.getDecodedFileName(
url = "https://kiwix.org/contributors/contributors_list.pdf",
src = null
)
assertThat(fileName).isEqualTo("contributors_list.pdf")
}
@Test
fun `test file name if extension doesn't exist`() {
val fileName = FileUtils.getDecodedFileName(url = "https://kiwix.org/contributors/", src = null)
assertThat(fileName).isEqualTo("")
}
@Test
fun `test file name if the url and src doesn't exist`() {
val fileName = FileUtils.getDecodedFileName(url = null, src = null)
assertThat(fileName).isEqualTo("")
}
@Test
fun `test file name if only file name exist`() {
val fileName = FileUtils.getDecodedFileName(src = "android_tutorials.pdf", url = null)
assertThat(fileName).isEqualTo("")
}
@Test
fun `test file name if url doesn't exist`() {
val fileName = FileUtils.getDecodedFileName(url = null, src = "/html/images/test.png")
assertThat(fileName).isEqualTo("test.png")
}
@Test
fun `test file name if url and src's extension doesn't exist`() {
val fileName = FileUtils.getDecodedFileName(url = null, src = "/html/images/")
assertThat(fileName).isEqualTo("")
}
} }