diff --git a/app/build.gradle b/app/build.gradle index 65597609..762094e5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,13 +2,13 @@ apply plugin: 'com.android.application' apply plugin: 'org.ajoberstar.grgit' android { - compileSdk 34 + compileSdk 35 namespace 'ai.elimu.content_provider' defaultConfig { applicationId "ai.elimu.content_provider" minSdkVersion 24 - targetSdkVersion 34 + targetSdkVersion 35 versionCode 1002029 versionName "1.2.29-SNAPSHOT" setProperty("archivesBaseName", "${applicationId}-${versionCode}") diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3587b8ea..552d6413 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -52,7 +52,12 @@ android:name=".provider.ImageContentProvider" android:authorities="${applicationId}.provider.image_provider" android:enabled="true" - android:exported="true" /> + android:exported="true" + android:grantUriPermissions="true"> + + segments = uri.getPathSegments(); + if (segments.size() < 2) { + throw new FileNotFoundException("Invalid URI: " + uri); + } + String fileId = segments.get(1); + + RoomDb roomDb = RoomDb.getDatabase(getContext()); + ImageDao imageDao = roomDb.imageDao(); + + long imageId; + try { + imageId = Long.parseLong(fileId); + } catch (NumberFormatException e) { + Log.e(TAG, "Failed to parse image ID: " + fileId, e); + throw new FileNotFoundException("Invalid image ID format: " + fileId); + } + + Image image = imageDao.load(imageId); + + if (image == null) { + throw new FileNotFoundException("File not found with id: " + imageId); + } + + File imageFile = FileHelper.getImageFile(image, getContext()); + if (imageFile == null) { + throw new FileNotFoundException("imageFile not found with id: " + imageId); + } + if (!imageFile.exists()) { + Log.e(TAG, "imageFile doesn't exist: " + imageFile.getAbsolutePath()); + throw new FileNotFoundException("File not found: " + imageFile.getAbsolutePath()); + } + return ParcelFileDescriptor.open(imageFile, ParcelFileDescriptor.MODE_READ_ONLY); + } + } diff --git a/app/src/main/java/ai/elimu/content_provider/util/FileHelper.java b/app/src/main/java/ai/elimu/content_provider/util/FileHelper.java index 54122675..369b7de4 100644 --- a/app/src/main/java/ai/elimu/content_provider/util/FileHelper.java +++ b/app/src/main/java/ai/elimu/content_provider/util/FileHelper.java @@ -3,8 +3,11 @@ import android.content.Context; import android.os.Environment; +import androidx.annotation.RestrictTo; + import java.io.File; +import ai.elimu.content_provider.room.entity.Image; import ai.elimu.model.v2.gson.content.AudioGson; import ai.elimu.model.v2.gson.content.ImageGson; import ai.elimu.model.v2.gson.content.VideoGson; @@ -19,8 +22,20 @@ public static File getImageFile(ImageGson imageGson, Context context) { return null; } File imagesDirectory = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES); - File file = new File(imagesDirectory, imageGson.getId() + "_r" + imageGson.getRevisionNumber() + "." + imageGson.getImageFormat().toString().toLowerCase()); - return file; + return new File(imagesDirectory, imageGson.getId() + + "_r" + imageGson.getRevisionNumber() + "." + + imageGson.getImageFormat().toString().toLowerCase()); + } + + @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) + public static File getImageFile(Image imageGson, Context context) { + if ((imageGson.getId() == null) || (imageGson.getRevisionNumber() == null)) { + return null; + } + File imagesDirectory = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES); + return new File(imagesDirectory, imageGson.getId() + + "_r" + imageGson.getRevisionNumber() + "." + + imageGson.getImageFormat().toString().toLowerCase()); } public static File getAudioFile(AudioGson audioGson, Context context) { diff --git a/app/src/main/res/xml/image_file_path.xml b/app/src/main/res/xml/image_file_path.xml new file mode 100644 index 00000000..f734c0c0 --- /dev/null +++ b/app/src/main/res/xml/image_file_path.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file