Merge pull request #11017 from JosJuice/saf-custom-cover

Android: Fix reading custom covers with SAF
This commit is contained in:
Mai 2022-09-01 00:27:28 -04:00 committed by GitHub
commit 11281b5cef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 67 additions and 15 deletions

View File

@ -61,7 +61,7 @@ public class GameFileCache
String path = dolphinIni.getString(Settings.SECTION_INI_GENERAL, String path = dolphinIni.getString(Settings.SECTION_INI_GENERAL,
SettingsFile.KEY_ISO_PATH_BASE + i, ""); SettingsFile.KEY_ISO_PATH_BASE + i, "");
if (path.startsWith("content://") ? ContentHandler.exists(path) : new File(path).exists()) if (ContentHandler.isContentUri(path) ? ContentHandler.exists(path) : new File(path).exists())
{ {
pathSet.add(path); pathSet.add(path);
} }

View File

@ -37,6 +37,11 @@ import java.util.function.Predicate;
public class ContentHandler public class ContentHandler
{ {
public static boolean isContentUri(@NonNull String pathOrUri)
{
return pathOrUri.startsWith("content://");
}
@Keep @Keep
public static int openFd(@NonNull String uri, @NonNull String mode) public static int openFd(@NonNull String uri, @NonNull String mode)
{ {
@ -336,7 +341,7 @@ public class ContentHandler
* provider to use URIs without any % characters. * provider to use URIs without any % characters.
*/ */
@NonNull @NonNull
private static Uri unmangle(@NonNull String uri) throws FileNotFoundException, SecurityException public static Uri unmangle(@NonNull String uri) throws FileNotFoundException, SecurityException
{ {
int lastComponentEnd = getLastComponentEnd(uri); int lastComponentEnd = getLastComponentEnd(uri);
int lastComponentStart = getLastComponentStart(uri, lastComponentEnd); int lastComponentStart = getLastComponentStart(uri, lastComponentEnd);

View File

@ -82,9 +82,16 @@ public final class FileBrowserHelper
return isPathEmptyOrValid(path.getStringGlobal()); return isPathEmptyOrValid(path.getStringGlobal());
} }
/**
* Returns true if at least one of the following applies:
*
* 1. The input is empty.
* 2. The input is something which is not a content URI.
* 3. The input is a content URI that points to a file that exists and we're allowed to access.
*/
public static boolean isPathEmptyOrValid(String path) public static boolean isPathEmptyOrValid(String path)
{ {
return !path.startsWith("content://") || ContentHandler.exists(path); return !ContentHandler.isContentUri(path) || ContentHandler.exists(path);
} }
public static void runAfterExtensionCheck(Context context, Uri uri, Set<String> validExtensions, public static void runAfterExtensionCheck(Context context, Uri uri, Set<String> validExtensions,

View File

@ -18,6 +18,7 @@ import org.dolphinemu.dolphinemu.model.GameFile;
import org.dolphinemu.dolphinemu.viewholders.GameViewHolder; import org.dolphinemu.dolphinemu.viewholders.GameViewHolder;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException;
public class PicassoUtils public class PicassoUtils
{ {
@ -54,12 +55,33 @@ public class PicassoUtils
gameViewHolder.textGameCaption.setVisibility(View.GONE); gameViewHolder.textGameCaption.setVisibility(View.GONE);
} }
String customCoverPath = gameFile.getCustomCoverPath();
Uri customCoverUri = null;
boolean customCoverExists = false;
if (ContentHandler.isContentUri(customCoverPath))
{
try
{
customCoverUri = ContentHandler.unmangle(customCoverPath);
customCoverExists = true;
}
catch (FileNotFoundException | SecurityException ignored)
{
// Let customCoverExists remain false
}
}
else
{
customCoverUri = Uri.parse(customCoverPath);
customCoverExists = new File(customCoverPath).exists();
}
Context context = imageView.getContext(); Context context = imageView.getContext();
File cover = new File(gameFile.getCustomCoverPath()); File cover;
if (cover.exists()) if (customCoverExists)
{ {
Picasso.get() Picasso.get()
.load(cover) .load(customCoverUri)
.noFade() .noFade()
.noPlaceholder() .noPlaceholder()
.fit() .fit()

View File

@ -34,6 +34,7 @@ import org.dolphinemu.dolphinemu.services.SyncProgramsJobService;
import org.dolphinemu.dolphinemu.ui.platform.Platform; import org.dolphinemu.dolphinemu.ui.platform.Platform;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -155,26 +156,43 @@ public class TvUtil
} }
/** /**
* Leanback lanucher requires a uri for poster art so we create a contentUri and * Leanback launcher requires a uri for poster art so we create a contentUri and
* pass that to LEANBACK_PACKAGE * pass that to LEANBACK_PACKAGE
*/ */
public static Uri buildBanner(GameFile game, Context context) public static Uri buildBanner(GameFile game, Context context)
{ {
Uri contentUri = null; Uri contentUri = null;
File cover;
try try
{ {
File cover = new File(game.getCustomCoverPath()); String customCoverPath = game.getCustomCoverPath();
if (cover.exists())
if (ContentHandler.isContentUri(customCoverPath))
{
try
{
contentUri = ContentHandler.unmangle(customCoverPath);
}
catch (FileNotFoundException | SecurityException ignored)
{
// Let contentUri remain null
}
}
else
{
if ((cover = new File(customCoverPath)).exists())
{
contentUri = getUriForFile(context, getFileProvider(context), cover);
}
}
if (contentUri == null && (cover = new File(game.getCoverPath(context))).exists())
{ {
contentUri = getUriForFile(context, getFileProvider(context), cover); contentUri = getUriForFile(context, getFileProvider(context), cover);
} }
else if ((cover = new File(game.getCoverPath(context))).exists())
{ context.grantUriPermission(LEANBACK_PACKAGE, contentUri, FLAG_GRANT_READ_URI_PERMISSION);
contentUri = getUriForFile(context, getFileProvider(context), cover);
}
context.grantUriPermission(LEANBACK_PACKAGE, contentUri,
FLAG_GRANT_READ_URI_PERMISSION);
} }
catch (Exception e) catch (Exception e)
{ {