From b316eab85d4f6fb4d2eb2d3b4f3bf64c70534d76 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 19 Oct 2020 16:59:32 +0200 Subject: [PATCH] post-install Intent to tell OsmAnd to import "installed" OBF OsmAnd will import map files from a file:// URL pointing to an OBF file, but this currently only works for file:// and not the proper content://. This uses a hack to disable the warning about file:// URIs but only for the final stage of installing the .obf file. Hopefully in the future, this can be changed to use a proper content:// URL as I suggested to them in this merge request: https://github.com/osmandapp/OsmAnd/pull/10043 --- .../main/java/org/fdroid/fdroid/data/Apk.java | 15 +++++--- .../installer/FileInstallerActivity.java | 37 +++++++++++++++++++ .../java/org/fdroid/fdroid/data/ApkTest.java | 11 +++++- .../fdroid/fdroid/installer/ApkCacheTest.java | 4 ++ 4 files changed, 60 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/org/fdroid/fdroid/data/Apk.java b/app/src/main/java/org/fdroid/fdroid/data/Apk.java index 89b1cd72b..abb480930 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/Apk.java +++ b/app/src/main/java/org/fdroid/fdroid/data/Apk.java @@ -569,12 +569,15 @@ public class Apk extends ValueObject implements Comparable, Parcelable { String fileExtension = MimeTypeMap.getFileExtensionFromUrl(this.getCanonicalUrl()); if (TextUtils.isEmpty(fileExtension)) return path; MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton(); - String[] mimeType = mimeTypeMap.getMimeTypeFromExtension(fileExtension).split("/"); - String topLevelType; - if (mimeType.length == 0) { - topLevelType = ""; - } else { - topLevelType = mimeType[0]; + String mimeType = mimeTypeMap.getMimeTypeFromExtension(fileExtension); + String topLevelType = null; + if (!TextUtils.isEmpty(mimeType)) { + String[] mimeTypeSections = mimeType.split("/"); + if (mimeTypeSections.length == 0) { + topLevelType = ""; + } else { + topLevelType = mimeTypeSections[0]; + } } if ("audio".equals(topLevelType)) { path = Environment.getExternalStoragePublicDirectory( diff --git a/app/src/main/java/org/fdroid/fdroid/installer/FileInstallerActivity.java b/app/src/main/java/org/fdroid/fdroid/installer/FileInstallerActivity.java index 23b804d0f..b8e513170 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/FileInstallerActivity.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/FileInstallerActivity.java @@ -5,8 +5,12 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; +import android.os.Build; import android.os.Bundle; +import android.os.StrictMode; +import android.util.Log; import android.view.ContextThemeWrapper; +import android.webkit.MimeTypeMap; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; @@ -21,6 +25,7 @@ import org.fdroid.fdroid.data.Apk; import java.io.File; import java.io.IOException; +import java.lang.reflect.Method; public class FileInstallerActivity extends FragmentActivity { @@ -161,12 +166,44 @@ public class FileInstallerActivity extends FragmentActivity { Toast.makeText(this, String.format(this.getString(R.string.app_installed_media), path.toString()), Toast.LENGTH_LONG).show(); installer.sendBroadcastInstall(canonicalUri, Installer.ACTION_INSTALL_COMPLETE); + postInstall(path); } else { installer.sendBroadcastInstall(canonicalUri, Installer.ACTION_INSTALL_INTERRUPTED); } finish(); } + /** + * Run any file-type-specific processes after the file has been copied into place. + *

+ * When this was written, OsmAnd only supported importing OBF files via a + * {@code file:///} URL, so this disables {@link android.os.FileUriExposedException}. + */ + private void postInstall(File path) { + if (path.getName().endsWith(".obf")) { + if (Build.VERSION.SDK_INT >= 24) { + try { + Method m = StrictMode.class.getMethod("disableDeathOnFileUriExposure"); + m.invoke(null); + } catch (Exception e) { + e.printStackTrace(); + } + } + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); + String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension("obf"); + intent.setDataAndType(Uri.fromFile(path), mimeType); + if (Build.VERSION.SDK_INT >= 23) { + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + } + if (intent.resolveActivity(getPackageManager()) != null) { + startActivity(intent); + } else { + Log.i(TAG, "No Activity available to handle " + intent); + } + } + } + private void uninstallPackage(Apk apk) { if (apk.isMediaInstalled(activity.getApplicationContext())) { File file = apk.getInstalledMediaFile(activity.getApplicationContext()); diff --git a/app/src/test/java/org/fdroid/fdroid/data/ApkTest.java b/app/src/test/java/org/fdroid/fdroid/data/ApkTest.java index b20314926..96bda89ec 100644 --- a/app/src/test/java/org/fdroid/fdroid/data/ApkTest.java +++ b/app/src/test/java/org/fdroid/fdroid/data/ApkTest.java @@ -2,7 +2,6 @@ package org.fdroid.fdroid.data; import android.content.ContextWrapper; import android.os.Environment; -import android.util.Log; import android.webkit.MimeTypeMap; import androidx.test.core.app.ApplicationProvider; import org.apache.commons.io.FileUtils; @@ -58,6 +57,16 @@ public class ApkTest { assertEquals(new File(context.getApplicationInfo().dataDir + "/ota"), path); } + @Test + public void testGetMediaInstallPathWithObf() { + Apk apk = new Apk(); + apk.apkName = "Norway_bouvet_europe_2.obf"; + apk.repoAddress = "https://example.com/fdroid/repo"; + assertFalse(apk.isApk()); + File path = apk.getMediaInstallPath(context); + assertEquals(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), path); + } + @Test public void testGetMediaInstallPathWithObfZip() throws IOException { Apk apk = new Apk(); diff --git a/app/src/test/java/org/fdroid/fdroid/installer/ApkCacheTest.java b/app/src/test/java/org/fdroid/fdroid/installer/ApkCacheTest.java index 6c5c33dbf..1069e0d6d 100644 --- a/app/src/test/java/org/fdroid/fdroid/installer/ApkCacheTest.java +++ b/app/src/test/java/org/fdroid/fdroid/installer/ApkCacheTest.java @@ -54,5 +54,9 @@ public class ApkCacheTest { new File(cacheDir, "example.com--1/Norway_bouvet_europe_2.obf.zip"), ApkCache.getApkDownloadPath(context, "https://example.com/fdroid/repo/Norway_bouvet_europe_2.obf.zip")); + assertEquals("Should work for OBF files also", + new File(cacheDir, "example.com--1/Norway_bouvet_europe_2.obf"), + ApkCache.getApkDownloadPath(context, + "https://example.com/fdroid/repo/Norway_bouvet_europe_2.obf")); } }