mirror of
https://github.com/Lime3DS/Lime3DS.git
synced 2026-06-01 12:15:03 -06:00
android: Fix launching applications through intent data in vanilla build (#1896)
* android: Fix launching applications through intent data in vanilla build * GameHelper.kt: Use Uri.scheme where applicable --------- Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
This commit is contained in:
parent
ae9972b6be
commit
3d5ba09eb1
@ -18,6 +18,7 @@ import android.os.Build
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
|
import android.os.ParcelFileDescriptor
|
||||||
import android.os.SystemClock
|
import android.os.SystemClock
|
||||||
import android.text.Editable
|
import android.text.Editable
|
||||||
import android.text.TextWatcher
|
import android.text.TextWatcher
|
||||||
@ -73,6 +74,7 @@ import org.citra.citra_emu.features.settings.model.SettingsViewModel
|
|||||||
import org.citra.citra_emu.features.settings.ui.SettingsActivity
|
import org.citra.citra_emu.features.settings.ui.SettingsActivity
|
||||||
import org.citra.citra_emu.features.settings.utils.SettingsFile
|
import org.citra.citra_emu.features.settings.utils.SettingsFile
|
||||||
import org.citra.citra_emu.model.Game
|
import org.citra.citra_emu.model.Game
|
||||||
|
import org.citra.citra_emu.utils.BuildUtil
|
||||||
import org.citra.citra_emu.utils.DirectoryInitialization
|
import org.citra.citra_emu.utils.DirectoryInitialization
|
||||||
import org.citra.citra_emu.utils.DirectoryInitialization.DirectoryInitializationState
|
import org.citra.citra_emu.utils.DirectoryInitialization.DirectoryInitializationState
|
||||||
import org.citra.citra_emu.utils.EmulationMenuSettings
|
import org.citra.citra_emu.utils.EmulationMenuSettings
|
||||||
@ -108,6 +110,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
|||||||
private val onPause = Runnable{ togglePause() }
|
private val onPause = Runnable{ togglePause() }
|
||||||
private val onShutdown = Runnable{ emulationState.stop() }
|
private val onShutdown = Runnable{ emulationState.stop() }
|
||||||
|
|
||||||
|
// Only used if a game is passed through intent on google play variant
|
||||||
|
private var gameFd: Int? = null
|
||||||
|
|
||||||
override fun onAttach(context: Context) {
|
override fun onAttach(context: Context) {
|
||||||
super.onAttach(context)
|
super.onAttach(context)
|
||||||
if (context is EmulationActivity) {
|
if (context is EmulationActivity) {
|
||||||
@ -125,27 +130,34 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
|||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
val intent = requireActivity().intent
|
val intent = requireActivity().intent
|
||||||
val intentUri: Uri? = intent.data
|
var intentUri: Uri? = intent.data
|
||||||
val oldIntentInfo = Pair(
|
val oldIntentInfo = Pair(
|
||||||
intent.getStringExtra("SelectedGame"),
|
intent.getStringExtra("SelectedGame"),
|
||||||
intent.getStringExtra("SelectedTitle")
|
intent.getStringExtra("SelectedTitle")
|
||||||
)
|
)
|
||||||
var intentGame: Game? = null
|
var intentGame: Game? = null
|
||||||
|
intentUri = if (intentUri == null && oldIntentInfo.first != null) {
|
||||||
|
Uri.parse(oldIntentInfo.first)
|
||||||
|
} else {
|
||||||
|
intentUri
|
||||||
|
}
|
||||||
if (intentUri != null) {
|
if (intentUri != null) {
|
||||||
intentGame = if (Game.extensions.contains(FileUtil.getExtension(intentUri))) {
|
if (!BuildUtil.isGooglePlayBuild) {
|
||||||
// isInstalled, addedToLibrary and mediaType do not matter here
|
// We need to build a special path as the incoming URI may be SAF exclusive
|
||||||
GameHelper.getGame(intentUri, isInstalled = false, addedToLibrary = false, mediaType = Game.MediaType.GAME_CARD)
|
Log.warning("[EmulationFragment] Cannot determine native path of URI \"" +
|
||||||
} else {
|
intentUri.toString() + "\", using file descriptor instead.")
|
||||||
null
|
gameFd = requireContext().contentResolver.openFileDescriptor(intentUri, "r")?.detachFd()
|
||||||
}
|
intentUri = if (gameFd != null) {
|
||||||
} else if (oldIntentInfo.first != null) {
|
Uri.parse("fd://" + gameFd.toString())
|
||||||
val gameUri = Uri.parse(oldIntentInfo.first)
|
} else {
|
||||||
intentGame = if (Game.extensions.contains(FileUtil.getExtension(gameUri))) {
|
null
|
||||||
// isInstalled, addedToLibrary and mediaType do not matter here
|
}
|
||||||
GameHelper.getGame(gameUri, isInstalled = false, addedToLibrary = false, mediaType = Game.MediaType.GAME_CARD)
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
}
|
||||||
|
intentGame =
|
||||||
|
intentUri?.let {
|
||||||
|
// isInstalled, addedToLibrary and mediaType do not matter here
|
||||||
|
GameHelper.getGame(it, isInstalled = false, addedToLibrary = false, mediaType = Game.MediaType.GAME_CARD)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val insertedCartridge = preferences.getString("insertedCartridge", "")
|
val insertedCartridge = preferences.getString("insertedCartridge", "")
|
||||||
@ -163,6 +175,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Log.info("[EmulationFragment] Starting application " + game.path)
|
||||||
|
|
||||||
// So this fragment doesn't restart on configuration changes; i.e. rotation.
|
// So this fragment doesn't restart on configuration changes; i.e. rotation.
|
||||||
retainInstance = true
|
retainInstance = true
|
||||||
emulationState = EmulationState(game.path)
|
emulationState = EmulationState(game.path)
|
||||||
@ -528,6 +542,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
|||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
EmulationLifecycleUtil.removeHook(onPause)
|
EmulationLifecycleUtil.removeHook(onPause)
|
||||||
EmulationLifecycleUtil.removeHook(onShutdown)
|
EmulationLifecycleUtil.removeHook(onShutdown)
|
||||||
|
if (gameFd != null) {
|
||||||
|
ParcelFileDescriptor.adoptFd(gameFd!!).close()
|
||||||
|
gameFd = null
|
||||||
|
}
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -222,6 +222,10 @@ object FileUtil {
|
|||||||
var filename = ""
|
var filename = ""
|
||||||
var c: Cursor? = null
|
var c: Cursor? = null
|
||||||
try {
|
try {
|
||||||
|
if (uri.scheme == "fd") {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
if (uri.scheme == "file") {
|
if (uri.scheme == "file") {
|
||||||
BuildUtil.assertNotGooglePlay()
|
BuildUtil.assertNotGooglePlay()
|
||||||
val file = File(uri.path!!);
|
val file = File(uri.path!!);
|
||||||
|
|||||||
@ -75,7 +75,11 @@ object GameHelper {
|
|||||||
if (BuildUtil.isGooglePlayBuild || FileUtil.isNativePath(filePath)) {
|
if (BuildUtil.isGooglePlayBuild || FileUtil.isNativePath(filePath)) {
|
||||||
gameInfo = GameInfo(filePath)
|
gameInfo = GameInfo(filePath)
|
||||||
} else {
|
} else {
|
||||||
nativePath = "!" + NativeLibrary.getNativePath(uri);
|
nativePath = if (uri.scheme == "fd") {
|
||||||
|
uri.toString()
|
||||||
|
} else {
|
||||||
|
"!" + NativeLibrary.getNativePath(uri)
|
||||||
|
};
|
||||||
gameInfo = GameInfo(nativePath)
|
gameInfo = GameInfo(nativePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -122,6 +122,16 @@ typedef struct stat file_stat_t;
|
|||||||
#define FERROR ferror
|
#define FERROR ferror
|
||||||
#define FFLUSH std::fflush
|
#define FFLUSH std::fflush
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define DUP_FD _dup
|
||||||
|
#define FDOPEN _fdopen
|
||||||
|
#define CLOSE_FD _close
|
||||||
|
#else
|
||||||
|
#define DUP_FD dup
|
||||||
|
#define FDOPEN fdopen
|
||||||
|
#define CLOSE_FD close
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// This namespace has various generic functions related to files and paths.
|
// This namespace has various generic functions related to files and paths.
|
||||||
@ -1262,6 +1272,44 @@ void IOFile::Swap(IOFile& other) noexcept {
|
|||||||
bool IOFile::Open() {
|
bool IOFile::Open() {
|
||||||
Close();
|
Close();
|
||||||
|
|
||||||
|
// Any filename with the format fd://<file_descriptor> represents a file that
|
||||||
|
// must be opened by duplicating the provided file_descriptor. This is used
|
||||||
|
// on Android vanilla builds when the ROM absolute path is not known.
|
||||||
|
if (filename.starts_with("fd://")) {
|
||||||
|
|
||||||
|
#if !defined(HAVE_LIBRETRO_VFS)
|
||||||
|
const std::string fd_str = filename.substr(5);
|
||||||
|
|
||||||
|
// Check that fd_str is not empty and contains only digits
|
||||||
|
if (fd_str.empty() || !std::all_of(fd_str.begin(), fd_str.end(), ::isdigit)) {
|
||||||
|
m_good = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fd = std::stoi(fd_str);
|
||||||
|
|
||||||
|
int dup_fd = DUP_FD(fd);
|
||||||
|
if (dup_fd == -1) {
|
||||||
|
m_good = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_file = FDOPEN(dup_fd, openmode.c_str());
|
||||||
|
if (!m_file) {
|
||||||
|
CLOSE_FD(dup_fd);
|
||||||
|
m_good = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_good = true;
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
// TODO: Add support for libretro vfs when needed.
|
||||||
|
m_good = false;
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// Open with FILE_SHARE_READ, FILE_SHARE_WRITE and FILE_SHARE_DELETE
|
// Open with FILE_SHARE_READ, FILE_SHARE_WRITE and FILE_SHARE_DELETE
|
||||||
// flags. This mimics linux behaviour as much as possible, which
|
// flags. This mimics linux behaviour as much as possible, which
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user