Use any image for local folders

This commit is contained in:
Herbert Reiter 2021-01-05 16:32:15 +01:00
parent 092e9a9a20
commit fd3b07cafb
2 changed files with 124 additions and 16 deletions

View File

@ -6,15 +6,13 @@ import android.media.MediaMetadataRetriever;
import android.net.Uri;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.documentfile.provider.DocumentFile;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
@ -34,6 +32,8 @@ import de.danoeh.antennapod.core.util.DownloadError;
public class LocalFeedUpdater {
static final String[] PREFERRED_FEED_IMAGE_FILENAMES = { "folder.jpg", "Folder.jpg", "folder.png", "Folder.png" };
public static void updateFeed(Feed feed, Context context) {
try {
tryUpdateFeed(feed, context);
@ -97,18 +97,7 @@ public class LocalFeedUpdater {
}
}
List<String> iconLocations = Arrays.asList("folder.jpg", "Folder.jpg", "folder.png", "Folder.png");
for (String iconLocation : iconLocations) {
DocumentFile image = documentFolder.findFile(iconLocation);
if (image != null) {
feed.setImageUrl(image.getUri().toString());
break;
}
}
if (StringUtils.isBlank(feed.getImageUrl())) {
// set default feed image
feed.setImageUrl(getDefaultIconUrl(context));
}
feed.setImageUrl(getImageUrl(context, documentFolder));
feed.getPreferences().setAutoDownload(false);
feed.getPreferences().setAutoDeleteAction(FeedPreferences.AutoDeleteAction.NO);
@ -122,6 +111,40 @@ public class LocalFeedUpdater {
DBTasks.updateFeed(context, feed, removeUnlistedItems);
}
/**
* Returns the image URL for the local feed.
*/
@NonNull
static String getImageUrl(@NonNull Context context, @NonNull DocumentFile documentFolder) {
String imageUrl = null;
// look for special file names
for (String iconLocation : PREFERRED_FEED_IMAGE_FILENAMES) {
DocumentFile image = documentFolder.findFile(iconLocation);
if (image != null) {
imageUrl = image.getUri().toString();
break;
}
}
// use the first image in the folder if existing
if (imageUrl == null) {
for (DocumentFile file : documentFolder.listFiles()) {
String mime = file.getType();
if (mime != null && (mime.startsWith("image/jpeg") || mime.startsWith("image/png"))) {
imageUrl = file.getUri().toString();
break;
}
}
}
// use default icon as fallback
if (imageUrl == null) {
imageUrl = getDefaultIconUrl(context);
}
return imageUrl;
}
/**
* Returns the URL of the default icon for a local feed. The URL refers to an app resource file.
*/
@ -161,7 +184,7 @@ public class LocalFeedUpdater {
return item;
}
private static void loadMetadata(FeedItem item, DocumentFile file, Context context) throws Exception {
private static void loadMetadata(FeedItem item, DocumentFile file, Context context) {
MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();
mediaMetadataRetriever.setDataSource(context, file.getUri());

View File

@ -3,6 +3,7 @@ package de.danoeh.antennapod.core.feed;
import android.app.Application;
import android.content.Context;
import android.media.MediaMetadataRetriever;
import android.net.Uri;
import android.webkit.MimeTypeMap;
import androidx.annotation.NonNull;
@ -33,6 +34,8 @@ import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.PodDBAdapter;
import static org.hamcrest.CoreMatchers.endsWith;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
@ -180,6 +183,66 @@ public class LocalFeedUpdaterTest {
assertEquals(24, calendar.get(Calendar.SECOND));
}
@Test
public void testGetImageUrl_NoImage() {
String defaultImageName = context.getResources().getResourceEntryName(R.raw.local_feed_default_icon);
{
// empty folder
DocumentFile documentFolder = mockDocumentFolder();
String imageUrl = LocalFeedUpdater.getImageUrl(context, documentFolder);
assertThat(imageUrl, endsWith(defaultImageName));
}
{
// no image file, with audio file
DocumentFile documentFolder = mockDocumentFolder(mockDocumentFile("audio.mp3", "audio/mp3"));
String imageUrl = LocalFeedUpdater.getImageUrl(context, documentFolder);
assertThat(imageUrl, endsWith(defaultImageName));
}
}
@Test
public void testGetImageUrl_PreferredImagesFilenames() {
for (String filename : LocalFeedUpdater.PREFERRED_FEED_IMAGE_FILENAMES) {
DocumentFile documentFolder = mockDocumentFolder(mockDocumentFile("audio.mp3", "audio/mp3"),
mockDocumentFile(filename, "image/jpeg")); // image MIME type doesn't matter
String imageUrl = LocalFeedUpdater.getImageUrl(context, documentFolder);
assertThat(imageUrl, endsWith(filename));
}
}
@Test
public void testGetImageUrl_OtherImageFilename() {
{
// .jpg file
DocumentFile documentFolder = mockDocumentFolder(mockDocumentFile("audio.mp3", "audio/mp3"),
mockDocumentFile("my-image.jpg", "image/jpeg"));
String imageUrl = LocalFeedUpdater.getImageUrl(context, documentFolder);
assertThat(imageUrl, endsWith("my-image.jpg"));
}
{
// .jpeg file
DocumentFile documentFolder = mockDocumentFolder(mockDocumentFile("audio.mp3", "audio/mp3"),
mockDocumentFile("my-image.jpeg", "image/jpeg"));
String imageUrl = LocalFeedUpdater.getImageUrl(context, documentFolder);
assertThat(imageUrl, endsWith("my-image.jpeg"));
}
{
// .png file
DocumentFile documentFolder = mockDocumentFolder(mockDocumentFile("audio.mp3", "audio/mp3"),
mockDocumentFile("my-image.png", "image/png"));
String imageUrl = LocalFeedUpdater.getImageUrl(context, documentFolder);
assertThat(imageUrl, endsWith("my-image.png"));
}
{
// unsupported image type
DocumentFile documentFolder = mockDocumentFolder(mockDocumentFile("audio.mp3", "audio/mp3"),
mockDocumentFile("my-image.svg", "image/svg+xml"));
String imageUrl = LocalFeedUpdater.getImageUrl(context, documentFolder);
String defaultImageName = context.getResources().getResourceEntryName(R.raw.local_feed_default_icon);
assertThat(imageUrl, endsWith(defaultImageName));
}
}
/**
* Fill ShadowMediaMetadataRetriever with dummy duration and title.
*
@ -238,4 +301,26 @@ public class LocalFeedUpdaterTest {
List<FeedItem> feedItems = DBReader.getFeedItemList(feed);
assertEquals(expectedItemCount, feedItems.size());
}
/**
* Create a DocumentFile mock object.
*/
@NonNull
private static DocumentFile mockDocumentFile(@NonNull String fileName, @NonNull String mimeType) {
DocumentFile file = mock(DocumentFile.class);
when(file.getName()).thenReturn(fileName);
when(file.getUri()).thenReturn(Uri.parse("file:///path/" + fileName));
when(file.getType()).thenReturn(mimeType);
return file;
}
/**
* Create a DocumentFile folder mock object with a list of files.
*/
@NonNull
private static DocumentFile mockDocumentFolder(DocumentFile... files) {
DocumentFile documentFolder = mock(DocumentFile.class);
when(documentFolder.listFiles()).thenReturn(files);
return documentFolder;
}
}