mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-09-08 06:42:21 -04:00
Merge pull request #1980 from kiwix/macgills/feature/1659-autoload-next-video
#1659 Autoload next video - replace content provider with WebResource…
This commit is contained in:
commit
d766ec7e90
@ -364,7 +364,9 @@
|
|||||||
<inspection_tool class="ReplaceSizeCheckWithIsNotEmpty" enabled="true" level="ERROR" enabled_by_default="true" />
|
<inspection_tool class="ReplaceSizeCheckWithIsNotEmpty" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||||
<inspection_tool class="ReplaceSizeZeroCheckWithIsEmpty" enabled="true" level="ERROR" enabled_by_default="true" />
|
<inspection_tool class="ReplaceSizeZeroCheckWithIsEmpty" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||||
<inspection_tool class="ReplaceStringFormatWithLiteral" enabled="true" level="ERROR" enabled_by_default="true" />
|
<inspection_tool class="ReplaceStringFormatWithLiteral" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||||
<inspection_tool class="ReplaceToStringWithStringTemplate" enabled="true" level="ERROR" enabled_by_default="true" />
|
<inspection_tool class="ReplaceToStringWithStringTemplate" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<scope name="Tests" level="INFORMATION" enabled="true" />
|
||||||
|
</inspection_tool>
|
||||||
<inspection_tool class="ReplaceToWithInfixForm" enabled="true" level="ERROR" enabled_by_default="true" />
|
<inspection_tool class="ReplaceToWithInfixForm" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||||
<inspection_tool class="ReplaceWithEnumMap" enabled="true" level="ERROR" enabled_by_default="true" />
|
<inspection_tool class="ReplaceWithEnumMap" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||||
<inspection_tool class="ReplaceWithOperatorAssignment" enabled="true" level="ERROR" enabled_by_default="true" />
|
<inspection_tool class="ReplaceWithOperatorAssignment" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||||
|
@ -39,7 +39,6 @@ import org.junit.runner.RunWith;
|
|||||||
import org.kiwix.kiwixmobile.core.CoreApp;
|
import org.kiwix.kiwixmobile.core.CoreApp;
|
||||||
import org.kiwix.kiwixmobile.core.di.components.DaggerTestComponent;
|
import org.kiwix.kiwixmobile.core.di.components.DaggerTestComponent;
|
||||||
import org.kiwix.kiwixmobile.core.di.components.TestComponent;
|
import org.kiwix.kiwixmobile.core.di.components.TestComponent;
|
||||||
import org.kiwix.kiwixmobile.core.reader.ZimContentProvider;
|
|
||||||
import org.kiwix.kiwixmobile.main.KiwixMainActivity;
|
import org.kiwix.kiwixmobile.main.KiwixMainActivity;
|
||||||
import org.kiwix.kiwixmobile.testutils.TestUtils;
|
import org.kiwix.kiwixmobile.testutils.TestUtils;
|
||||||
import org.kiwix.kiwixmobile.utils.KiwixIdlingResource;
|
import org.kiwix.kiwixmobile.utils.KiwixIdlingResource;
|
||||||
@ -92,8 +91,6 @@ public class NetworkTest {
|
|||||||
|
|
||||||
CoreApp.setCoreComponent(component);
|
CoreApp.setCoreComponent(component);
|
||||||
|
|
||||||
ZimContentProvider zimContentProvider = new ZimContentProvider();
|
|
||||||
CoreApp.getCoreComponent().inject(zimContentProvider);
|
|
||||||
component.inject(this);
|
component.inject(this);
|
||||||
InputStream library = NetworkTest.class.getClassLoader().getResourceAsStream("library.xml");
|
InputStream library = NetworkTest.class.getClassLoader().getResourceAsStream("library.xml");
|
||||||
InputStream metalinks =
|
InputStream metalinks =
|
||||||
|
@ -6,9 +6,6 @@ buildscript {
|
|||||||
dependencies {
|
dependencies {
|
||||||
classpath(Libs.com_android_tools_build_gradle)
|
classpath(Libs.com_android_tools_build_gradle)
|
||||||
classpath(Libs.kotlin_gradle_plugin)
|
classpath(Libs.kotlin_gradle_plugin)
|
||||||
classpath(Libs.ktlint_gradle)
|
|
||||||
classpath(Libs.jacoco_android)
|
|
||||||
classpath(Libs.detekt_gradle_plugin)
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
}
|
}
|
||||||
|
@ -89,7 +89,7 @@ object Versions {
|
|||||||
|
|
||||||
const val core_ktx: String = "1.2.0"
|
const val core_ktx: String = "1.2.0"
|
||||||
|
|
||||||
const val kiwixlib: String = "9.1.0"
|
const val kiwixlib: String = "9.1.2"
|
||||||
|
|
||||||
const val material: String = "1.1.0-beta02" // available: "1.1.0"
|
const val material: String = "1.1.0-beta02" // available: "1.1.0"
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
<Whitelist>
|
<Whitelist>
|
||||||
<ID>EmptyFunctionBlock:BooksOnDiskViewHolder.kt$BookOnDiskViewHolder.BookViewHolder${ }</ID>
|
<ID>EmptyFunctionBlock:BooksOnDiskViewHolder.kt$BookOnDiskViewHolder.BookViewHolder${ }</ID>
|
||||||
<ID>EmptyFunctionBlock:FetchDownloadMonitor.kt$FetchDownloadMonitor.<no name provided>${}</ID>
|
<ID>EmptyFunctionBlock:FetchDownloadMonitor.kt$FetchDownloadMonitor.<no name provided>${}</ID>
|
||||||
|
<ID>ForbiddenComment:JNIInitialiser.kt$JNIInitialiser$// TODO: Consider surfacing to user</ID>
|
||||||
<ID>LongParameterList:MainMenu.kt$MainMenu.Factory$( menu: Menu, webViews: MutableList<KiwixWebView>, urlIsValid: Boolean, menuClickListener: MenuClickListener, disableReadAloud: Boolean, disableTabs: Boolean )</ID>
|
<ID>LongParameterList:MainMenu.kt$MainMenu.Factory$( menu: Menu, webViews: MutableList<KiwixWebView>, urlIsValid: Boolean, menuClickListener: MenuClickListener, disableReadAloud: Boolean, disableTabs: Boolean )</ID>
|
||||||
<ID>MagicNumber:ArticleCount.kt$ArticleCount$1000.0</ID>
|
<ID>MagicNumber:ArticleCount.kt$ArticleCount$1000.0</ID>
|
||||||
<ID>MagicNumber:ArticleCount.kt$ArticleCount$3</ID>
|
<ID>MagicNumber:ArticleCount.kt$ArticleCount$3</ID>
|
||||||
@ -12,6 +13,7 @@
|
|||||||
<ID>MagicNumber:DownloaderModule.kt$DownloaderModule$5</ID>
|
<ID>MagicNumber:DownloaderModule.kt$DownloaderModule$5</ID>
|
||||||
<ID>MagicNumber:FetchDownloadRequester.kt$10</ID>
|
<ID>MagicNumber:FetchDownloadRequester.kt$10</ID>
|
||||||
<ID>MagicNumber:FileUtils.kt$FileUtils$3</ID>
|
<ID>MagicNumber:FileUtils.kt$FileUtils$3</ID>
|
||||||
|
<ID>MagicNumber:JNIInitialiser.kt$JNIInitialiser$1024</ID>
|
||||||
<ID>MagicNumber:KiloByte.kt$KiloByte$1024.0</ID>
|
<ID>MagicNumber:KiloByte.kt$KiloByte$1024.0</ID>
|
||||||
<ID>MagicNumber:MainMenu.kt$MainMenu$99</ID>
|
<ID>MagicNumber:MainMenu.kt$MainMenu$99</ID>
|
||||||
<ID>MagicNumber:SearchResultGenerator.kt$ZimSearchResultGenerator$200</ID>
|
<ID>MagicNumber:SearchResultGenerator.kt$ZimSearchResultGenerator$200</ID>
|
||||||
@ -20,6 +22,7 @@
|
|||||||
<ID>MagicNumber:Seconds.kt$Seconds$60.0</ID>
|
<ID>MagicNumber:Seconds.kt$Seconds$60.0</ID>
|
||||||
<ID>NestedBlockDepth:FileUtils.kt$FileUtils$deleteZimFile</ID>
|
<ID>NestedBlockDepth:FileUtils.kt$FileUtils$deleteZimFile</ID>
|
||||||
<ID>NestedBlockDepth:ImageUtils.kt$ImageUtils$getBitmapFromView</ID>
|
<ID>NestedBlockDepth:ImageUtils.kt$ImageUtils$getBitmapFromView</ID>
|
||||||
|
<ID>NestedBlockDepth:JNIInitialiser.kt$JNIInitialiser$loadICUData</ID>
|
||||||
<ID>NestedBlockDepth:StorageDeviceUtils.kt$StorageDeviceUtils$canWrite</ID>
|
<ID>NestedBlockDepth:StorageDeviceUtils.kt$StorageDeviceUtils$canWrite</ID>
|
||||||
<ID>PackageNaming:ArticleCount.kt$package org.kiwix.kiwixmobile.core.zim_manager.fileselect_view</ID>
|
<ID>PackageNaming:ArticleCount.kt$package org.kiwix.kiwixmobile.core.zim_manager.fileselect_view</ID>
|
||||||
<ID>PackageNaming:BookOnDiskDelegate.kt$package org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter</ID>
|
<ID>PackageNaming:BookOnDiskDelegate.kt$package org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter</ID>
|
||||||
@ -36,6 +39,7 @@
|
|||||||
<ID>ReturnCount:FileUtils.kt$FileUtils$@JvmStatic fun hasPart(file: File): Boolean</ID>
|
<ID>ReturnCount:FileUtils.kt$FileUtils$@JvmStatic fun hasPart(file: File): Boolean</ID>
|
||||||
<ID>ReturnCount:FileUtils.kt$FileUtils$@Synchronized private fun deleteZimFileParts(path: String): Boolean</ID>
|
<ID>ReturnCount:FileUtils.kt$FileUtils$@Synchronized private fun deleteZimFileParts(path: String): Boolean</ID>
|
||||||
<ID>ReturnCount:ImageUtils.kt$ImageUtils$private fun getBitmapFromView(width: Int, height: Int, viewToDrawFrom: View): Bitmap?</ID>
|
<ID>ReturnCount:ImageUtils.kt$ImageUtils$private fun getBitmapFromView(width: Int, height: Int, viewToDrawFrom: View): Bitmap?</ID>
|
||||||
|
<ID>TooGenericExceptionCaught:JNIInitialiser.kt$JNIInitialiser$e: Exception</ID>
|
||||||
<ID>TooGenericExceptionThrown:AbstractContentProvider.kt$AbstractContentProvider$throw RuntimeException("Operation not supported")</ID>
|
<ID>TooGenericExceptionThrown:AbstractContentProvider.kt$AbstractContentProvider$throw RuntimeException("Operation not supported")</ID>
|
||||||
<ID>TooGenericExceptionThrown:AdapterDelegateManager.kt$AdapterDelegateManager$throw RuntimeException("No delegate registered for $item")</ID>
|
<ID>TooGenericExceptionThrown:AdapterDelegateManager.kt$AdapterDelegateManager$throw RuntimeException("No delegate registered for $item")</ID>
|
||||||
<ID>TooGenericExceptionThrown:Bytes.kt$Bytes$throw RuntimeException("impossible value $size")</ID>
|
<ID>TooGenericExceptionThrown:Bytes.kt$Bytes$throw RuntimeException("impossible value $size")</ID>
|
||||||
@ -51,7 +55,6 @@
|
|||||||
<ID>TooManyFunctions:NewBookDao.kt$NewBookDao$NewBookDao</ID>
|
<ID>TooManyFunctions:NewBookDao.kt$NewBookDao$NewBookDao</ID>
|
||||||
<ID>TooManyFunctions:Repository.kt$Repository$Repository</ID>
|
<ID>TooManyFunctions:Repository.kt$Repository$Repository</ID>
|
||||||
<ID>TooManyFunctions:ZimFileReader.kt$ZimFileReader$ZimFileReader</ID>
|
<ID>TooManyFunctions:ZimFileReader.kt$ZimFileReader$ZimFileReader</ID>
|
||||||
<ID>TooManyFunctions:ZimReaderContainer.kt$ZimReaderContainer$ZimReaderContainer</ID>
|
|
||||||
<ID>TopLevelPropertyNaming:Bytes.kt$const val Eb = Pb * 1024</ID>
|
<ID>TopLevelPropertyNaming:Bytes.kt$const val Eb = Pb * 1024</ID>
|
||||||
<ID>TopLevelPropertyNaming:Bytes.kt$const val Gb = Mb * 1024</ID>
|
<ID>TopLevelPropertyNaming:Bytes.kt$const val Gb = Mb * 1024</ID>
|
||||||
<ID>TopLevelPropertyNaming:Bytes.kt$const val Kb = 1 * 1024L</ID>
|
<ID>TopLevelPropertyNaming:Bytes.kt$const val Kb = 1 * 1024L</ID>
|
||||||
|
@ -29,11 +29,6 @@
|
|||||||
|
|
||||||
<activity android:name=".bookmark.BookmarksActivity" />
|
<activity android:name=".bookmark.BookmarksActivity" />
|
||||||
|
|
||||||
<provider
|
|
||||||
android:name=".reader.ZimContentProvider"
|
|
||||||
android:authorities="${applicationId}.zim.base"
|
|
||||||
android:exported="true" />
|
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".error.ErrorActivity"
|
android:name=".error.ErrorActivity"
|
||||||
android:process=":error_activity" />
|
android:process=":error_activity" />
|
||||||
|
@ -50,6 +50,14 @@ public abstract class CoreApp extends Application {
|
|||||||
@Inject
|
@Inject
|
||||||
KiwixDatabase kiwixDatabase;
|
KiwixDatabase kiwixDatabase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The init of this class does the work of initializing,
|
||||||
|
* simply injecting it is all that there is to be done
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Inject
|
||||||
|
JNIInitialiser jniInitialiser;
|
||||||
|
|
||||||
public static CoreApp getInstance() {
|
public static CoreApp getInstance() {
|
||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Kiwix Android
|
||||||
|
* Copyright (c) 2020 Kiwix <android.kiwix.org>
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.kiwix.kiwixmobile.core
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.Log
|
||||||
|
import org.kiwix.kiwixlib.JNIKiwix
|
||||||
|
import org.kiwix.kiwixmobile.core.utils.TAG_KIWIX
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileOutputStream
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
internal class JNIInitialiser @Inject constructor(context: Context, jniKiwix: JNIKiwix) {
|
||||||
|
init {
|
||||||
|
loadICUData(context)?.let(jniKiwix::setDataDirectory)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadICUData(context: Context): String? {
|
||||||
|
return try {
|
||||||
|
val icuDir = File(context.filesDir, "icu")
|
||||||
|
if (!icuDir.exists()) {
|
||||||
|
icuDir.mkdirs()
|
||||||
|
}
|
||||||
|
val icuFileNames = context.assets.list("icu") ?: emptyArray()
|
||||||
|
for (icuFileName in icuFileNames) {
|
||||||
|
val icuDataFile = File(icuDir, icuFileName)
|
||||||
|
if (!icuDataFile.exists()) {
|
||||||
|
FileOutputStream(icuDataFile).use { outputStream ->
|
||||||
|
context.assets.open("icu/$icuFileName").use { inputStream ->
|
||||||
|
inputStream.copyTo(outputStream, 1024)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
icuDir.absolutePath
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.w(TAG_KIWIX, "Error copying icu data file", e)
|
||||||
|
// TODO: Consider surfacing to user
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,53 +0,0 @@
|
|||||||
/*
|
|
||||||
* Kiwix Android
|
|
||||||
* Copyright (c) 2019 Kiwix <android.kiwix.org>
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.kiwix.kiwixmobile.core.data
|
|
||||||
|
|
||||||
import android.content.ContentProvider
|
|
||||||
import android.content.ContentValues
|
|
||||||
import android.database.Cursor
|
|
||||||
import android.net.Uri
|
|
||||||
|
|
||||||
internal abstract class AbstractContentProvider : ContentProvider() {
|
|
||||||
override fun query(
|
|
||||||
url: Uri,
|
|
||||||
projection: Array<String>?,
|
|
||||||
selection: String?,
|
|
||||||
selectionArgs: Array<String>?,
|
|
||||||
sort: String?
|
|
||||||
): Cursor? {
|
|
||||||
throw RuntimeException("Operation not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun insert(uri: Uri, initialValues: ContentValues?): Uri? {
|
|
||||||
throw RuntimeException("Operation not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun update(
|
|
||||||
uri: Uri,
|
|
||||||
values: ContentValues?,
|
|
||||||
where: String?,
|
|
||||||
whereArgs: Array<String>?
|
|
||||||
): Int {
|
|
||||||
throw RuntimeException("Operation not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun delete(uri: Uri, where: String?, whereArgs: Array<String>?): Int {
|
|
||||||
throw RuntimeException("Operation not supported")
|
|
||||||
}
|
|
||||||
}
|
|
@ -47,7 +47,6 @@ import org.kiwix.kiwixmobile.core.error.ErrorActivity
|
|||||||
import org.kiwix.kiwixmobile.core.help.HelpActivity
|
import org.kiwix.kiwixmobile.core.help.HelpActivity
|
||||||
import org.kiwix.kiwixmobile.core.history.HistoryModule
|
import org.kiwix.kiwixmobile.core.history.HistoryModule
|
||||||
import org.kiwix.kiwixmobile.core.main.KiwixWebView
|
import org.kiwix.kiwixmobile.core.main.KiwixWebView
|
||||||
import org.kiwix.kiwixmobile.core.reader.ZimContentProvider
|
|
||||||
import org.kiwix.kiwixmobile.core.reader.ZimFileReader
|
import org.kiwix.kiwixmobile.core.reader.ZimFileReader
|
||||||
import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer
|
import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer
|
||||||
import org.kiwix.kiwixmobile.core.search.SearchActivity
|
import org.kiwix.kiwixmobile.core.search.SearchActivity
|
||||||
@ -101,7 +100,6 @@ interface CoreComponent {
|
|||||||
fun notificationManager(): NotificationManager
|
fun notificationManager(): NotificationManager
|
||||||
|
|
||||||
fun inject(application: CoreApp)
|
fun inject(application: CoreApp)
|
||||||
fun inject(zimContentProvider: ZimContentProvider)
|
|
||||||
fun inject(kiwixWebView: KiwixWebView)
|
fun inject(kiwixWebView: KiwixWebView)
|
||||||
fun inject(storageSelectDialog: StorageSelectDialog)
|
fun inject(storageSelectDialog: StorageSelectDialog)
|
||||||
|
|
||||||
|
@ -1391,7 +1391,7 @@ public abstract class CoreMainActivity extends BaseActivity
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private String contentUrl(String articleUrl) {
|
private String contentUrl(String articleUrl) {
|
||||||
return Uri.parse(ZimFileReader.CONTENT_URI + articleUrl).toString();
|
return Uri.parse(ZimFileReader.CONTENT_PREFIX + articleUrl).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@ -1680,7 +1680,7 @@ public abstract class CoreMainActivity extends BaseActivity
|
|||||||
@Override
|
@Override
|
||||||
public void webViewLongClick(final String url) {
|
public void webViewLongClick(final String url) {
|
||||||
boolean handleEvent = false;
|
boolean handleEvent = false;
|
||||||
if (url.startsWith(ZimFileReader.CONTENT_URI.toString())) {
|
if (url.startsWith(ZimFileReader.CONTENT_PREFIX)) {
|
||||||
// This is my web site, so do not override; let my WebView load the page
|
// This is my web site, so do not override; let my WebView load the page
|
||||||
handleEvent = true;
|
handleEvent = true;
|
||||||
} else if (url.startsWith("file://")) {
|
} else if (url.startsWith("file://")) {
|
||||||
|
@ -24,16 +24,19 @@ import android.util.Log;
|
|||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.webkit.MimeTypeMap;
|
import android.webkit.MimeTypeMap;
|
||||||
|
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 java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import org.kiwix.kiwixmobile.core.CoreApp;
|
import org.kiwix.kiwixmobile.core.CoreApp;
|
||||||
import org.kiwix.kiwixmobile.core.R;
|
import org.kiwix.kiwixmobile.core.R;
|
||||||
import org.kiwix.kiwixmobile.core.reader.ZimFileReader;
|
|
||||||
import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer;
|
import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer;
|
||||||
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil;
|
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil;
|
||||||
|
|
||||||
import static org.kiwix.kiwixmobile.core.main.CoreMainActivity.HOME_URL;
|
import static org.kiwix.kiwixmobile.core.main.CoreMainActivity.HOME_URL;
|
||||||
|
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.utils.ConstantsKt.EXTRA_EXTERNAL_LINK;
|
import static org.kiwix.kiwixmobile.core.utils.ConstantsKt.EXTRA_EXTERNAL_LINK;
|
||||||
import static org.kiwix.kiwixmobile.core.utils.ConstantsKt.TAG_KIWIX;
|
import static org.kiwix.kiwixmobile.core.utils.ConstantsKt.TAG_KIWIX;
|
||||||
|
|
||||||
@ -65,7 +68,7 @@ public abstract class CoreWebViewClient extends WebViewClient {
|
|||||||
view.loadUrl(zimReaderContainer.getRedirect(url));
|
view.loadUrl(zimReaderContainer.getRedirect(url));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (url.startsWith(ZimFileReader.CONTENT_URI.toString())) {
|
if (url.startsWith(CONTENT_PREFIX)) {
|
||||||
return handleEpubAndPdf(url);
|
return handleEpubAndPdf(url);
|
||||||
}
|
}
|
||||||
if (url.startsWith("file://")) {
|
if (url.startsWith("file://")) {
|
||||||
@ -76,7 +79,7 @@ public abstract class CoreWebViewClient extends WebViewClient {
|
|||||||
// Allow javascript for HTML functions and code execution (EX: night mode)
|
// Allow javascript for HTML functions and code execution (EX: night mode)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (url.startsWith(ZimFileReader.UI_URI.toString())) {
|
if (url.startsWith(UI_URI.toString())) {
|
||||||
Log.e("KiwixWebViewClient", "UI Url " + url + " not supported.");
|
Log.e("KiwixWebViewClient", "UI Url " + url + " not supported.");
|
||||||
//TODO: Document this code - what's a UI_URL?
|
//TODO: Document this code - what's a UI_URL?
|
||||||
return true;
|
return true;
|
||||||
@ -137,4 +140,14 @@ public abstract class CoreWebViewClient extends WebViewClient {
|
|||||||
view.removeAllViews();
|
view.removeAllViews();
|
||||||
view.addView(home);
|
view.addView(home);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
|
||||||
|
if (url.startsWith(CONTENT_PREFIX)) {
|
||||||
|
return zimReaderContainer.load(url);
|
||||||
|
} else {
|
||||||
|
return super.shouldInterceptRequest(view, url);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,120 +0,0 @@
|
|||||||
/*
|
|
||||||
* Kiwix Android
|
|
||||||
* Copyright (c) 2019 Kiwix <android.kiwix.org>
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.kiwix.kiwixmobile.core.reader;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.ParcelFileDescriptor;
|
|
||||||
import android.util.Log;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import org.kiwix.kiwixlib.JNIKiwix;
|
|
||||||
import org.kiwix.kiwixmobile.core.CoreApp;
|
|
||||||
import org.kiwix.kiwixmobile.core.data.AbstractContentProvider;
|
|
||||||
|
|
||||||
import static org.kiwix.kiwixmobile.core.utils.ConstantsKt.TAG_KIWIX;
|
|
||||||
|
|
||||||
public class ZimContentProvider extends AbstractContentProvider {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public JNIKiwix jniKiwix;
|
|
||||||
@Inject
|
|
||||||
ZimReaderContainer zimReaderContainer;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCreate() {
|
|
||||||
CoreApp.getCoreComponent().inject(this);
|
|
||||||
setIcuDataDirectory();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getType(Uri uri) {
|
|
||||||
return zimReaderContainer.readMimeType(uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ParcelFileDescriptor openFile(Uri uri, String mode) {
|
|
||||||
return zimReaderContainer.load(uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setIcuDataDirectory() {
|
|
||||||
String icuDirPath = loadICUData(getContext());
|
|
||||||
if (icuDirPath != null) {
|
|
||||||
Log.d(TAG_KIWIX, "Setting the ICU directory path to " + icuDirPath);
|
|
||||||
jniKiwix.setDataDirectory(icuDirPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String loadICUData(Context context) {
|
|
||||||
try {
|
|
||||||
File icuDir = new File(context.getFilesDir(), "icu");
|
|
||||||
if (!icuDir.exists()) {
|
|
||||||
icuDir.mkdirs();
|
|
||||||
}
|
|
||||||
String[] icuFileNames = context.getAssets().list("icu");
|
|
||||||
for (int i = 0; i < icuFileNames.length; i++) {
|
|
||||||
String icuFileName = icuFileNames[i];
|
|
||||||
File icuDataFile = new File(icuDir, icuFileName);
|
|
||||||
if (!icuDataFile.exists()) {
|
|
||||||
InputStream in = context.getAssets().open("icu/" + icuFileName);
|
|
||||||
OutputStream out = new FileOutputStream(icuDataFile);
|
|
||||||
byte[] buf = new byte[1024];
|
|
||||||
int len;
|
|
||||||
while ((len = in.read(buf)) > 0) {
|
|
||||||
out.write(buf, 0, len);
|
|
||||||
}
|
|
||||||
in.close();
|
|
||||||
out.flush();
|
|
||||||
out.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return icuDir.getAbsolutePath();
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.w(TAG_KIWIX, "Error copying icu data file", e);
|
|
||||||
//TODO: Consider surfacing to user
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getFulltextIndexPath(String file) {
|
|
||||||
String[] names = { file, file };
|
|
||||||
|
|
||||||
/* File might be a ZIM chunk like foobar.zimaa */
|
|
||||||
if (!names[0].substring(names[0].length() - 3).equals("zim")) {
|
|
||||||
names[0] = names[0].substring(0, names[0].length() - 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Try to find a *.idx fulltext file/directory beside the ZIM
|
|
||||||
* file. Returns <zimfile>.zim.idx or <zimfile>.zimaa.idx. */
|
|
||||||
for (String name : names) {
|
|
||||||
File f = new File(name + ".idx");
|
|
||||||
if (f.exists() && f.isDirectory()) {
|
|
||||||
return f.getPath();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If no separate fulltext index file found then returns the ZIM
|
|
||||||
* file path itself (embedded fulltext index) */
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
}
|
|
@ -17,14 +17,13 @@
|
|||||||
*/
|
*/
|
||||||
package org.kiwix.kiwixmobile.core.reader
|
package org.kiwix.kiwixmobile.core.reader
|
||||||
|
|
||||||
|
import android.content.res.AssetFileDescriptor
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.ParcelFileDescriptor
|
import android.os.ParcelFileDescriptor
|
||||||
import android.os.ParcelFileDescriptor.AutoCloseOutputStream
|
|
||||||
import android.os.ParcelFileDescriptor.dup
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.webkit.MimeTypeMap
|
import android.webkit.MimeTypeMap
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import io.reactivex.Single
|
import io.reactivex.Completable
|
||||||
import io.reactivex.schedulers.Schedulers
|
import io.reactivex.schedulers.Schedulers
|
||||||
import org.kiwix.kiwixlib.JNIKiwixException
|
import org.kiwix.kiwixlib.JNIKiwixException
|
||||||
import org.kiwix.kiwixlib.JNIKiwixInt
|
import org.kiwix.kiwixlib.JNIKiwixInt
|
||||||
@ -34,14 +33,16 @@ import org.kiwix.kiwixlib.Pair
|
|||||||
import org.kiwix.kiwixmobile.core.CoreApp
|
import org.kiwix.kiwixmobile.core.CoreApp
|
||||||
import org.kiwix.kiwixmobile.core.NightModeConfig
|
import org.kiwix.kiwixmobile.core.NightModeConfig
|
||||||
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity.Book
|
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity.Book
|
||||||
import org.kiwix.kiwixmobile.core.reader.ZimFileReader.Companion.CONTENT_URI
|
import org.kiwix.kiwixmobile.core.reader.ZimFileReader.Companion.CONTENT_PREFIX
|
||||||
import org.kiwix.kiwixmobile.core.search.SearchSuggestion
|
import org.kiwix.kiwixmobile.core.search.SearchSuggestion
|
||||||
import org.kiwix.kiwixmobile.core.utils.files.FileUtils
|
import org.kiwix.kiwixmobile.core.utils.files.FileUtils
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileDescriptor
|
import java.io.FileInputStream
|
||||||
import java.io.FileOutputStream
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.RandomAccessFile
|
import java.io.InputStream
|
||||||
|
import java.io.OutputStream
|
||||||
|
import java.io.PipedInputStream
|
||||||
|
import java.io.PipedOutputStream
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
private const val TAG = "ZimFileReader"
|
private const val TAG = "ZimFileReader"
|
||||||
@ -80,7 +81,7 @@ class ZimFileReader constructor(
|
|||||||
val description: String get() = jniKiwixReader.description
|
val description: String get() = jniKiwixReader.description
|
||||||
val favicon: String? get() = jniKiwixReader.favicon
|
val favicon: String? get() = jniKiwixReader.favicon
|
||||||
val language: String get() = jniKiwixReader.language
|
val language: String get() = jniKiwixReader.language
|
||||||
val tags: String get() = "${getContent(Uri.parse("M/Tags"))}"
|
val tags: String get() = "${getContent("M/Tags")}"
|
||||||
private val mediaCount: Int?
|
private val mediaCount: Int?
|
||||||
get() = try {
|
get() = try {
|
||||||
jniKiwixReader.mediaCount
|
jniKiwixReader.mediaCount
|
||||||
@ -112,8 +113,9 @@ class ZimFileReader constructor(
|
|||||||
fun getRandomArticleUrl(): String? =
|
fun getRandomArticleUrl(): String? =
|
||||||
valueOfJniStringAfter(jniKiwixReader::getRandomPage)
|
valueOfJniStringAfter(jniKiwixReader::getRandomPage)
|
||||||
|
|
||||||
fun load(uri: Uri): ParcelFileDescriptor {
|
fun load(uri: String): InputStream? {
|
||||||
if ("$uri".matches(VIDEO_REGEX)) {
|
val extension = uri.substringAfterLast(".")
|
||||||
|
if (videoExtensions.any { it == extension }) {
|
||||||
try {
|
try {
|
||||||
return loadVideo(uri)
|
return loadVideo(uri)
|
||||||
} catch (ioException: IOException) {
|
} catch (ioException: IOException) {
|
||||||
@ -123,7 +125,7 @@ class ZimFileReader constructor(
|
|||||||
return loadContent(uri)
|
return loadContent(uri)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readMimeType(uri: Uri) = "$uri".removeArguments().let {
|
fun readMimeType(uri: String) = uri.removeArguments().let {
|
||||||
it.mimeType?.takeIf(String::isNotEmpty) ?: mimeTypeFromReader(it)
|
it.mimeType?.takeIf(String::isNotEmpty) ?: mimeTypeFromReader(it)
|
||||||
}.also { Log.d(TAG, "getting mimetype for $uri = $it") }
|
}.also { Log.d(TAG, "getting mimetype for $uri = $it") }
|
||||||
|
|
||||||
@ -134,78 +136,73 @@ class ZimFileReader constructor(
|
|||||||
fun getRedirect(url: String) = "${toRedirect(url)}"
|
fun getRedirect(url: String) = "${toRedirect(url)}"
|
||||||
|
|
||||||
fun isRedirect(url: String) =
|
fun isRedirect(url: String) =
|
||||||
url.startsWith("$CONTENT_URI") && url != getRedirect(url)
|
url.startsWith(CONTENT_PREFIX) && url != getRedirect(url)
|
||||||
|
|
||||||
private fun toRedirect(url: String) =
|
private fun toRedirect(url: String) =
|
||||||
"$CONTENT_URI${jniKiwixReader.checkUrl(url.toUri().filePath)}".toUri()
|
"$CONTENT_PREFIX${jniKiwixReader.checkUrl(url.toUri().filePath)}".toUri()
|
||||||
|
|
||||||
private fun loadContent(uri: Uri) =
|
private fun loadContent(uri: String) =
|
||||||
try {
|
try {
|
||||||
ParcelFileDescriptor.createPipe().also {
|
val outputStream = PipedOutputStream()
|
||||||
streamZimContentToPipe(uri, AutoCloseOutputStream(it[1]))
|
PipedInputStream(outputStream).also { streamZimContentToPipe(uri, outputStream) }
|
||||||
}[0]
|
|
||||||
} catch (ioException: IOException) {
|
} catch (ioException: IOException) {
|
||||||
throw IOException("Could not open pipe for $uri", ioException)
|
throw IOException("Could not open pipe for $uri", ioException)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadVideo(uri: Uri): ParcelFileDescriptor {
|
private fun loadVideo(uri: String): InputStream? {
|
||||||
val infoPair = jniKiwixReader.getDirectAccessInformation(uri.filePath)
|
val infoPair = jniKiwixReader.getDirectAccessInformation(uri.filePath)
|
||||||
if (infoPair == null || !File(infoPair.filename).exists()) {
|
if (infoPair == null || !File(infoPair.filename).exists()) {
|
||||||
return loadVideoFromCache(uri)
|
return loadVideoFromCache(uri)
|
||||||
}
|
}
|
||||||
return dup(infoPair.fileDescriptor)
|
return AssetFileDescriptor(
|
||||||
|
infoPair.parcelFileDescriptor,
|
||||||
|
infoPair.offset,
|
||||||
|
jniKiwixReader.getArticleSize(uri.filePath)
|
||||||
|
).createInputStream()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
private fun loadVideoFromCache(uri: Uri): ParcelFileDescriptor {
|
private fun loadVideoFromCache(uri: String): FileInputStream {
|
||||||
val outputFile = File(
|
return File(
|
||||||
FileUtils.getFileCacheDir(CoreApp.getInstance()),
|
FileUtils.getFileCacheDir(CoreApp.getInstance()),
|
||||||
"$uri".substringAfterLast("/")
|
uri.substringAfterLast("/")
|
||||||
)
|
).apply { writeBytes(getContent(uri)) }
|
||||||
FileOutputStream(outputFile).use { it.write(getContent(uri)) }
|
.inputStream()
|
||||||
return ParcelFileDescriptor.open(outputFile, ParcelFileDescriptor.MODE_READ_ONLY)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun streamZimContentToPipe(
|
private fun getContent(url: String) = getContentAndMimeType(url).let { (content, _) -> content }
|
||||||
uri: Uri,
|
|
||||||
outputStream: AutoCloseOutputStream
|
private fun streamZimContentToPipe(uri: String, outputStream: OutputStream) {
|
||||||
) {
|
Completable.fromAction {
|
||||||
Single.just(Unit)
|
try {
|
||||||
.subscribeOn(Schedulers.io())
|
outputStream.use {
|
||||||
.observeOn(Schedulers.io())
|
getContentAndMimeType(uri).let { (content: ByteArray, mimeType: String) ->
|
||||||
.subscribe(
|
if ("text/css" == mimeType && nightModeConfig.isNightModeActive()) {
|
||||||
{
|
it.write(INVERT_IMAGES_VIDEO.toByteArray(Charsets.UTF_8))
|
||||||
try {
|
|
||||||
outputStream.use {
|
|
||||||
val mime = JNIKiwixString()
|
|
||||||
val size = JNIKiwixInt()
|
|
||||||
val url = JNIKiwixString(uri.filePath.removeArguments())
|
|
||||||
val content = getContent(url = url, mime = mime, size = size)
|
|
||||||
if ("text/css" == mime.value && nightModeConfig.isNightModeActive()) {
|
|
||||||
it.write(INVERT_IMAGES_VIDEO.toByteArray(Charsets.UTF_8))
|
|
||||||
}
|
|
||||||
it.write(content)
|
|
||||||
Log.d(
|
|
||||||
TAG,
|
|
||||||
"reading ${url.value}(mime: ${mime.value}, size: ${size.value}) finished."
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
} catch (ioException: IOException) {
|
it.write(content)
|
||||||
Log.e(TAG, "error writing pipe for $uri", ioException)
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Throwable::printStackTrace
|
} catch (ioException: IOException) {
|
||||||
)
|
Log.e(TAG, "error writing pipe for $uri", ioException)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.subscribe({ }, Throwable::printStackTrace)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getContent(uri: Uri) = getContent(JNIKiwixString(uri.filePath.removeArguments()))
|
private fun getContentAndMimeType(uri: String) = with(JNIKiwixString()) {
|
||||||
|
getContent(url = JNIKiwixString(uri.filePath.removeArguments()), mime = this) to value
|
||||||
|
}
|
||||||
|
|
||||||
private fun getContent(
|
private fun getContent(
|
||||||
url: JNIKiwixString = JNIKiwixString(),
|
url: JNIKiwixString = JNIKiwixString(),
|
||||||
jniKiwixString: JNIKiwixString = JNIKiwixString(),
|
jniKiwixString: JNIKiwixString = JNIKiwixString(),
|
||||||
mime: JNIKiwixString = JNIKiwixString(),
|
mime: JNIKiwixString = JNIKiwixString(),
|
||||||
size: JNIKiwixInt = JNIKiwixInt()
|
size: JNIKiwixInt = JNIKiwixInt()
|
||||||
) = jniKiwixReader.getContent(url, jniKiwixString, mime, size)
|
) = jniKiwixReader.getContent(url, jniKiwixString, mime, size).also {
|
||||||
|
Log.d(TAG, "reading ${url.value}(mime: ${mime.value}, size: ${size.value}) finished.")
|
||||||
|
}
|
||||||
|
|
||||||
private fun valueOfJniStringAfter(jniStringFunction: (JNIKiwixString) -> Boolean) =
|
private fun valueOfJniStringAfter(jniStringFunction: (JNIKiwixString) -> Boolean) =
|
||||||
JNIKiwixString().takeIf { jniStringFunction(it) }?.value
|
JNIKiwixString().takeIf { jniStringFunction(it) }?.value
|
||||||
@ -233,9 +230,11 @@ class ZimFileReader constructor(
|
|||||||
*/
|
*/
|
||||||
@JvmField
|
@JvmField
|
||||||
val UI_URI: Uri? = Uri.parse("content://org.kiwix.ui/")
|
val UI_URI: Uri? = Uri.parse("content://org.kiwix.ui/")
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val CONTENT_URI: Uri? =
|
val CONTENT_PREFIX =
|
||||||
Uri.parse("content://${CoreApp.getInstance().packageName}.zim.base/")
|
Uri.parse("content://${CoreApp.getInstance().packageName}.zim.base/").toString()
|
||||||
|
|
||||||
private val INVERT_IMAGES_VIDEO =
|
private val INVERT_IMAGES_VIDEO =
|
||||||
"""
|
"""
|
||||||
img, video, div[poster], div#header {
|
img, video, div[poster], div#header {
|
||||||
@ -251,18 +250,18 @@ class ZimFileReader constructor(
|
|||||||
filter: invert(0);
|
filter: invert(0);
|
||||||
}
|
}
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
private val VIDEO_REGEX = Regex("([^\\s]+(\\.(?i)(3gp|mp4|m4a|webm|mkv|ogg|ogv))\$)")
|
private val videoExtensions = listOf("3gp", "mp4", "m4a", "webm", "mkv", "ogg", "ogv")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun String.removeArguments() = substringBefore("?")
|
private fun String.removeArguments() = substringBefore("?")
|
||||||
private val Pair.fileDescriptor: FileDescriptor?
|
|
||||||
get() = RandomAccessFile(filename, "r").apply { seek(offset.toLong()) }.fd
|
|
||||||
private val Uri.filePath: String
|
private val Uri.filePath: String
|
||||||
get() = toString().filePath
|
get() = toString().filePath
|
||||||
private val String.filePath: String
|
private val String.filePath: String
|
||||||
get() = substringAfter("$CONTENT_URI").substringBefore("#")
|
get() = substringAfter(CONTENT_PREFIX).substringBefore("#")
|
||||||
private val String.mimeType: String?
|
private val String.mimeType: String?
|
||||||
get() = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
|
get() = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
|
||||||
MimeTypeMap.getFileExtensionFromUrl(this)
|
MimeTypeMap.getFileExtensionFromUrl(this)
|
||||||
)
|
)
|
||||||
|
private val Pair.parcelFileDescriptor: ParcelFileDescriptor?
|
||||||
|
get() = ParcelFileDescriptor.open(File(filename), ParcelFileDescriptor.MODE_READ_ONLY)
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.kiwix.kiwixmobile.core.reader
|
package org.kiwix.kiwixmobile.core.reader
|
||||||
|
|
||||||
import android.net.Uri
|
import android.webkit.WebResourceResponse
|
||||||
import org.kiwix.kiwixlib.JNIKiwixSearcher
|
import org.kiwix.kiwixlib.JNIKiwixSearcher
|
||||||
import org.kiwix.kiwixmobile.core.reader.ZimFileReader.Factory
|
import org.kiwix.kiwixmobile.core.reader.ZimFileReader.Factory
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@ -48,10 +48,6 @@ class ZimReaderContainer @Inject constructor(
|
|||||||
else null
|
else null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readMimeType(uri: Uri) = zimFileReader?.readMimeType(uri)
|
|
||||||
|
|
||||||
fun load(uri: Uri) = zimFileReader?.load(uri)
|
|
||||||
|
|
||||||
fun searchSuggestions(prefix: String, count: Int) =
|
fun searchSuggestions(prefix: String, count: Int) =
|
||||||
zimFileReader?.searchSuggestions(prefix, count) ?: false
|
zimFileReader?.searchSuggestions(prefix, count) ?: false
|
||||||
|
|
||||||
@ -67,8 +63,15 @@ class ZimReaderContainer @Inject constructor(
|
|||||||
fun getNextResult() = jniKiwixSearcher?.nextResult?.let { SearchResult(it.title) }
|
fun getNextResult() = jniKiwixSearcher?.nextResult?.let { SearchResult(it.title) }
|
||||||
fun isRedirect(url: String): Boolean = zimFileReader?.isRedirect(url) == true
|
fun isRedirect(url: String): Boolean = zimFileReader?.isRedirect(url) == true
|
||||||
fun getRedirect(url: String): String = zimFileReader?.getRedirect(url) ?: ""
|
fun getRedirect(url: String): String = zimFileReader?.getRedirect(url) ?: ""
|
||||||
|
fun load(url: String) =
|
||||||
|
WebResourceResponse(
|
||||||
|
zimFileReader?.readMimeType(url),
|
||||||
|
Charsets.UTF_8.name(),
|
||||||
|
zimFileReader?.load(url)
|
||||||
|
)
|
||||||
|
|
||||||
val zimFile get() = zimFileReader?.zimFile
|
val zimFile get() = zimFileReader?.zimFile
|
||||||
|
|
||||||
val zimCanonicalPath get() = zimFileReader?.zimFile?.canonicalPath
|
val zimCanonicalPath get() = zimFileReader?.zimFile?.canonicalPath
|
||||||
val zimFileTitle get() = zimFileReader?.title
|
val zimFileTitle get() = zimFileReader?.title
|
||||||
val mainPage get() = zimFileReader?.mainPage
|
val mainPage get() = zimFileReader?.mainPage
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package org.kiwix.kiwixmobile.core
|
package org.kiwix.kiwixmobile.core
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
import io.mockk.clearAllMocks
|
import io.mockk.clearAllMocks
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
@ -58,6 +59,8 @@ class StorageObserverTest {
|
|||||||
setScheduler(Schedulers.trampoline())
|
setScheduler(Schedulers.trampoline())
|
||||||
mockkStatic(CoreApp::class)
|
mockkStatic(CoreApp::class)
|
||||||
every { CoreApp.getInstance().packageName } returns "pkg"
|
every { CoreApp.getInstance().packageName } returns "pkg"
|
||||||
|
mockkStatic(Uri::class)
|
||||||
|
every { Uri.parse(any()).toString() } returns "pkg"
|
||||||
zimFileReader = mockk()
|
zimFileReader = mockk()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user