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
This commit is contained in:
Hans-Christoph Steiner 2020-10-19 16:59:32 +02:00
parent 8cf267ea6c
commit b316eab85d
No known key found for this signature in database
GPG Key ID: 3E177817BA1B9BFA
4 changed files with 60 additions and 7 deletions

View File

@ -569,12 +569,15 @@ public class Apk extends ValueObject implements Comparable<Apk>, 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(

View File

@ -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.
* <p>
* 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());

View File

@ -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();

View File

@ -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"));
}
}