diff --git a/app/build.gradle b/app/build.gradle index c4a4d69335d8..ffdb42b0588e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -31,8 +31,8 @@ android { defaultConfig { applicationId "at.tomtasche.reader" minSdkVersion 23 - compileSdkVersion 34 - targetSdkVersion 34 + compileSdkVersion 35 + targetSdkVersion 35 testApplicationId "at.tomtasche.reader.test" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -149,7 +149,6 @@ dependencies { implementation 'com.google.android.material:material:1.12.0' implementation 'androidx.webkit:webkit:1.11.0' - implementation 'com.github.huzongyao:AndroidMagic:v1.1.2' implementation 'com.viliussutkus89:assetextractor-android:1.3.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1' diff --git a/app/conandeployer.py b/app/conandeployer.py index 1ea75762d8b2..6cc0b50cc30a 100644 --- a/app/conandeployer.py +++ b/app/conandeployer.py @@ -52,3 +52,12 @@ def deploy(graph, output_folder: str, **kwargs): f"{output_folder}/fontconfig", **copytree_kwargs, ) + + if "libmagic" in deps: + dep = deps["libmagic"] + conanfile.output.info(f"Deploying libmagic to {output_folder}") + shutil.copytree( + f"{dep.package_folder}/res", + f"{output_folder}/libmagic", + **copytree_kwargs, + ) diff --git a/app/conanfile.txt b/app/conanfile.txt index 5c79d58a0cf2..774c45414516 100644 --- a/app/conanfile.txt +++ b/app/conanfile.txt @@ -1,5 +1,5 @@ [requires] -odrcore/5.0.7 +odrcore/5.1.1 [generators] CMakeToolchain diff --git a/app/src/main/cpp/core_wrapper.cpp b/app/src/main/cpp/core_wrapper.cpp index 8101881f7311..372b19ebbfdf 100644 --- a/app/src/main/cpp/core_wrapper.cpp +++ b/app/src/main/cpp/core_wrapper.cpp @@ -88,16 +88,29 @@ Java_at_tomtasche_reader_background_CoreWrapper_setGlobalParams(JNIEnv *env, jcl std::string fontconfigDataPath = getStringField(env, paramsClass, params, "fontconfigDataPath"); std::string popplerDataPath = getStringField(env, paramsClass, params, "popplerDataPath"); std::string pdf2htmlexDataPath = getStringField(env, paramsClass, params, "pdf2htmlexDataPath"); + std::string libmagicDatabasePath = getStringField(env, paramsClass, params, "libmagicDatabasePath"); std::string customTmpfilePath = getStringField(env, paramsClass, params, "customTmpfilePath"); odr::GlobalParams::set_odr_core_data_path(odrCoreDataPath); odr::GlobalParams::set_fontconfig_data_path(fontconfigDataPath); odr::GlobalParams::set_poppler_data_path(popplerDataPath); odr::GlobalParams::set_pdf2htmlex_data_path(pdf2htmlexDataPath); + odr::GlobalParams::set_libmagic_database_path(libmagicDatabasePath); tmpfile_hack::set_tmpfile_directory(customTmpfilePath); } +JNIEXPORT jstring JNICALL +Java_at_tomtasche_reader_background_CoreWrapper_mimetypeNative(JNIEnv *env, jclass clazz, jstring path) { + auto logger = std::make_shared(); + + std::string pathCpp = convertString(env, path); + std::string mimetypeCpp = std::string(odr::mimetype(pathCpp)); + jstring mimetype = env->NewStringUTF(mimetypeCpp.c_str()); + + return mimetype; +} + JNIEXPORT jobject JNICALL Java_at_tomtasche_reader_background_CoreWrapper_parseNative(JNIEnv *env, jclass clazz, jobject options) { diff --git a/app/src/main/cpp/core_wrapper.hpp b/app/src/main/cpp/core_wrapper.hpp index 9c29e6175192..8804ba1293a1 100644 --- a/app/src/main/cpp/core_wrapper.hpp +++ b/app/src/main/cpp/core_wrapper.hpp @@ -8,6 +8,10 @@ JNIEXPORT void JNICALL Java_at_tomtasche_reader_background_CoreWrapper_setGlobalParams(JNIEnv *env, jclass clazz, jobject params); +JNIEXPORT jstring JNICALL +Java_at_tomtasche_reader_background_CoreWrapper_mimetypeNative(JNIEnv *env, jclass clazz, + jstring path); + JNIEXPORT jobject JNICALL Java_at_tomtasche_reader_background_CoreWrapper_parseNative(JNIEnv *env, jclass clazz, jobject options); diff --git a/app/src/main/java/at/tomtasche/reader/background/CoreWrapper.java b/app/src/main/java/at/tomtasche/reader/background/CoreWrapper.java index b894ef3f0a62..37cbe6085a91 100644 --- a/app/src/main/java/at/tomtasche/reader/background/CoreWrapper.java +++ b/app/src/main/java/at/tomtasche/reader/background/CoreWrapper.java @@ -18,6 +18,8 @@ public static class GlobalParams { public String fontconfigDataPath; public String popplerDataPath; public String pdf2htmlexDataPath; + public String libmagicDatabasePath; + public String customTmpfilePath; } @@ -29,6 +31,7 @@ public static void initialize(Context context) { File fontconfigDataDirectory = new File(assetsDirectory, "fontconfig"); File popplerDataDirectory = new File(assetsDirectory, "poppler"); File pdf2htmlexDataDirectory = new File(assetsDirectory, "pdf2htmlex"); + File libmagicDataDirectory = new File(assetsDirectory, "libmagic"); AssetExtractor ae = new AssetExtractor(context.getAssets()); ae.setOverwrite(); @@ -36,16 +39,24 @@ public static void initialize(Context context) { ae.extract(assetsDirectory, "core/fontconfig"); ae.extract(assetsDirectory, "core/poppler"); ae.extract(assetsDirectory, "core/pdf2htmlex"); + ae.extract(assetsDirectory, "core/libmagic"); CoreWrapper.GlobalParams globalParams = new CoreWrapper.GlobalParams(); globalParams.coreDataPath = odrCoreDataDirectory.getAbsolutePath(); globalParams.fontconfigDataPath = fontconfigDataDirectory.getAbsolutePath(); globalParams.popplerDataPath = popplerDataDirectory.getAbsolutePath(); globalParams.pdf2htmlexDataPath = pdf2htmlexDataDirectory.getAbsolutePath(); + globalParams.libmagicDatabasePath = new File(libmagicDataDirectory, "magic.mgc").getAbsolutePath(); globalParams.customTmpfilePath = context.getCacheDir().getAbsolutePath(); CoreWrapper.setGlobalParams(globalParams); } + public static String mimetype(String path) { + return mimetypeNative(path); + } + + private static native String mimetypeNative(String path); + public static class CoreOptions { public boolean ooxml; public boolean txt; diff --git a/app/src/main/java/at/tomtasche/reader/background/MetadataLoader.java b/app/src/main/java/at/tomtasche/reader/background/MetadataLoader.java index 8705a52868f5..66c9f52ab45b 100644 --- a/app/src/main/java/at/tomtasche/reader/background/MetadataLoader.java +++ b/app/src/main/java/at/tomtasche/reader/background/MetadataLoader.java @@ -6,8 +6,6 @@ import android.provider.OpenableColumns; import android.webkit.MimeTypeMap; -import com.hzy.libmagic.MagicApi; - import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -21,30 +19,6 @@ public MetadataLoader(Context context) { super(context, LoaderType.METADATA); } - private boolean initMagicFromAssets() { - InputStream inputStream = null; - try { - inputStream = context.getAssets().open("magic.mgc"); - int length = inputStream.available(); - byte[] buffer = new byte[length]; - if (inputStream.read(buffer) > 0) { - return MagicApi.loadFromBytes(buffer, MagicApi.MAGIC_MIME_TYPE | MagicApi.MAGIC_COMPRESS_TRANSP) == 0; - } - } catch (Throwable e) { - crashManager.log(e); - } finally { - if (inputStream != null) { - try { - inputStream.close(); - } catch (IOException e) { - crashManager.log(e); - } - } - } - - return false; - } - @Override public boolean isSupported(Options options) { return true; @@ -113,22 +87,20 @@ public void loadSync(Options options) { String[] fileSplit = options.filename.split("\\."); String extension = fileSplit.length > 0 ? fileSplit[fileSplit.length - 1] : "N/A"; - String type = null; + String mimetype = null; try { - if (initMagicFromAssets()) { - type = MagicApi.magicFile(cachedFile.getAbsolutePath()); - } + mimetype = CoreWrapper.mimetype(cachedFile.getAbsolutePath()); } catch (Throwable e) { crashManager.log(e); } - if (type == null) { - type = context.getContentResolver().getType(uri); + if (mimetype == null) { + mimetype = context.getContentResolver().getType(uri); } - if (type == null) { + if (mimetype == null) { try { - type = URLConnection.guessContentTypeFromName(filename); + mimetype = URLConnection.guessContentTypeFromName(filename); } catch (Exception e) { // Samsung S7 Edge crashes with java.lang.StringIndexOutOfBoundsException crashManager.log(e); @@ -138,7 +110,7 @@ public void loadSync(Options options) { if (type == null) { try { try (InputStream tempStream = new FileInputStream(cachedFile)) { - type = URLConnection.guessContentTypeFromStream(tempStream); + mimetype = URLConnection.guessContentTypeFromStream(tempStream); } } catch (Exception e) { crashManager.log(e); @@ -146,19 +118,19 @@ public void loadSync(Options options) { } if (type != null) { - extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(type); + extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimetype); } else { - type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(options.fileExtension); + mimetype = MimeTypeMap.getSingleton().getMimeTypeFromExtension(options.fileExtension); } if (extension != null) { options.fileExtension = extension; } - if (type != null) { - options.fileType = type; + if (mimetype != null) { + options.fileType = mimetype; } - if ("inode/x-empty".equals(type)) { + if ("inode/x-empty".equals(mimetype)) { throw new FileNotFoundException(); } @@ -183,20 +155,4 @@ public void loadSync(Options options) { callOnError(result, e); } } - - @Override - public void close() { - super.close(); - - backgroundHandler.post(new Runnable() { - @Override - public void run() { - try { - MagicApi.close(); - } catch (Throwable e) { - crashManager.log(e); - } - } - }); - } } diff --git a/app/src/main/res/values-v35/themes.xml b/app/src/main/res/values-v35/themes.xml new file mode 100644 index 000000000000..9c7918795209 --- /dev/null +++ b/app/src/main/res/values-v35/themes.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/build.gradle b/build.gradle index ab59aa6280f4..efcf249f58d4 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.android.application' version '8.5.2' apply false + id 'com.android.application' version '8.13.1' apply false id 'com.google.gms.google-services'version '4.4.2' apply false id 'com.google.firebase.crashlytics' version '3.0.2' apply false id 'app.opendocument.conanandroidgradleplugin' version '0.9.6' apply false diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 09523c0e5490..37f853b1c84d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME