mirror of
https://github.com/Lime3DS/Lime3DS.git
synced 2026-03-27 05:49:12 -06:00
Read media type and pass it to UninstallProgram
This commit is contained in:
parent
e878174df8
commit
32da5ea0ae
@ -25,6 +25,7 @@ import androidx.fragment.app.DialogFragment
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import org.citra.citra_emu.activities.EmulationActivity
|
||||
import org.citra.citra_emu.model.Game
|
||||
import org.citra.citra_emu.utils.BuildUtil
|
||||
import org.citra.citra_emu.utils.FileUtil
|
||||
import org.citra.citra_emu.utils.Log
|
||||
@ -132,7 +133,27 @@ object NativeLibrary {
|
||||
* If not set, it auto-detects a location
|
||||
*/
|
||||
external fun setUserDirectory(directory: String)
|
||||
external fun getInstalledGamePaths(): Array<String?>
|
||||
|
||||
data class InstalledGame(
|
||||
val path: String,
|
||||
val mediaType: Game.MediaType
|
||||
)
|
||||
fun getInstalledGamePaths(): Array<InstalledGame> {
|
||||
val games = getInstalledGamePathsImpl()
|
||||
|
||||
return games.mapNotNull { entry ->
|
||||
entry?.let {
|
||||
val sep = it.lastIndexOf('|')
|
||||
if (sep == -1) return@mapNotNull null
|
||||
|
||||
val path = it.substring(0, sep)
|
||||
val mediaType = Game.MediaType.fromInt(it.substring(sep + 1).toInt())
|
||||
|
||||
InstalledGame(path, mediaType!!)
|
||||
}
|
||||
}.toTypedArray()
|
||||
}
|
||||
private external fun getInstalledGamePathsImpl(): Array<String?>
|
||||
|
||||
// Create the config.ini file.
|
||||
external fun createConfigFile()
|
||||
@ -230,7 +251,10 @@ object NativeLibrary {
|
||||
external fun playTimeManagerGetPlayTime(titleId: Long): Long
|
||||
external fun playTimeManagerGetCurrentTitleId(): Long
|
||||
|
||||
external fun uninstallTitle(titleId: Long): Boolean
|
||||
private external fun uninstallTitle(titleId: Long, mediaType: Int): Boolean
|
||||
fun uninstallTitle(titleId: Long, mediaType: Game.MediaType): Boolean {
|
||||
return uninstallTitle(titleId, mediaType.value)
|
||||
}
|
||||
|
||||
private var coreErrorAlertResult = false
|
||||
private val coreErrorAlertLock = Object()
|
||||
|
||||
@ -330,9 +330,9 @@ class GameAdapter(
|
||||
popup.setOnMenuItemClickListener { menuItem ->
|
||||
val uninstallAction: () -> Unit = {
|
||||
when (menuItem.itemId) {
|
||||
R.id.game_context_uninstall -> NativeLibrary.uninstallTitle(titleId)
|
||||
R.id.game_context_uninstall_dlc -> NativeLibrary.uninstallTitle(dlcTitleId)
|
||||
R.id.game_context_uninstall_updates -> NativeLibrary.uninstallTitle(updateTitleId)
|
||||
R.id.game_context_uninstall -> NativeLibrary.uninstallTitle(titleId, game.mediaType)
|
||||
R.id.game_context_uninstall_dlc -> NativeLibrary.uninstallTitle(dlcTitleId, Game.MediaType.SDMC)
|
||||
R.id.game_context_uninstall_updates -> NativeLibrary.uninstallTitle(updateTitleId, Game.MediaType.SDMC)
|
||||
}
|
||||
ViewModelProvider(activity)[GamesViewModel::class.java].reloadGames(true)
|
||||
bottomSheetDialog.dismiss()
|
||||
|
||||
@ -133,14 +133,16 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
||||
var intentGame: Game? = null
|
||||
if (intentUri != null) {
|
||||
intentGame = if (Game.extensions.contains(FileUtil.getExtension(intentUri))) {
|
||||
GameHelper.getGame(intentUri, isInstalled = false, addedToLibrary = false)
|
||||
// isInstalled, addedToLibrary and mediaType do not matter here
|
||||
GameHelper.getGame(intentUri, isInstalled = false, addedToLibrary = false, mediaType = Game.MediaType.GAME_CARD)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} else if (oldIntentInfo.first != null) {
|
||||
val gameUri = Uri.parse(oldIntentInfo.first)
|
||||
intentGame = if (Game.extensions.contains(FileUtil.getExtension(gameUri))) {
|
||||
GameHelper.getGame(gameUri, isInstalled = false, addedToLibrary = false)
|
||||
// isInstalled, addedToLibrary and mediaType do not matter here
|
||||
GameHelper.getGame(gameUri, isInstalled = false, addedToLibrary = false, mediaType = Game.MediaType.GAME_CARD)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
@ -20,6 +20,7 @@ class Game(
|
||||
val description: String = "",
|
||||
val path: String = "",
|
||||
val titleId: Long = 0L,
|
||||
val mediaType: MediaType = MediaType.GAME_CARD,
|
||||
val company: String = "",
|
||||
val regions: String = "",
|
||||
val isInstalled: Boolean = false,
|
||||
@ -58,10 +59,23 @@ class Game(
|
||||
result = 31 * result + regions.hashCode()
|
||||
result = 31 * result + path.hashCode()
|
||||
result = 31 * result + titleId.hashCode()
|
||||
result = 31 * result + mediaType.hashCode()
|
||||
result = 31 * result + company.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
enum class MediaType(val value: Int) {
|
||||
NAND(0),
|
||||
SDMC(1),
|
||||
GAME_CARD(2);
|
||||
|
||||
companion object {
|
||||
fun fromInt(value: Int): MediaType? {
|
||||
return MediaType.entries.find { it.value == value }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val allExtensions: Set<String> get() = extensions + badExtensions
|
||||
|
||||
|
||||
@ -32,7 +32,7 @@ object GameHelper {
|
||||
|
||||
addGamesRecursive(games, FileUtil.listFiles(gamesUri), 3)
|
||||
NativeLibrary.getInstalledGamePaths().forEach {
|
||||
games.add(getGame(Uri.parse(it), isInstalled = true, addedToLibrary = true))
|
||||
games.add(getGame(Uri.parse(it.path), isInstalled = true, addedToLibrary = true, it.mediaType))
|
||||
}
|
||||
|
||||
// Cache list of games found on disk
|
||||
@ -62,13 +62,13 @@ object GameHelper {
|
||||
addGamesRecursive(games, FileUtil.listFiles(it.uri), depth - 1)
|
||||
} else {
|
||||
if (Game.allExtensions.contains(FileUtil.getExtension(it.uri))) {
|
||||
games.add(getGame(it.uri, isInstalled = false, addedToLibrary = true))
|
||||
games.add(getGame(it.uri, isInstalled = false, addedToLibrary = true, Game.MediaType.GAME_CARD))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getGame(uri: Uri, isInstalled: Boolean, addedToLibrary: Boolean): Game {
|
||||
fun getGame(uri: Uri, isInstalled: Boolean, addedToLibrary: Boolean, mediaType: Game.MediaType): Game {
|
||||
val filePath = uri.toString()
|
||||
var nativePath: String? = null
|
||||
var gameInfo: GameInfo?
|
||||
@ -95,6 +95,7 @@ object GameHelper {
|
||||
nativePath!!
|
||||
},
|
||||
gameInfo?.getTitleID() ?: 0,
|
||||
mediaType,
|
||||
gameInfo?.getCompany() ?: "",
|
||||
if (isEncrypted) { CitraApplication.appContext.getString(R.string.unsupported_encrypted) } else { gameInfo?.getRegions() ?: "" },
|
||||
isInstalled,
|
||||
|
||||
@ -652,34 +652,38 @@ void Java_org_citra_citra_1emu_NativeLibrary_setUserDirectory(JNIEnv* env,
|
||||
FileUtil::SetCurrentDir(GetJString(env, j_directory));
|
||||
}
|
||||
|
||||
jobjectArray Java_org_citra_citra_1emu_NativeLibrary_getInstalledGamePaths(
|
||||
jobjectArray Java_org_citra_citra_1emu_NativeLibrary_getInstalledGamePathsImpl(
|
||||
JNIEnv* env, [[maybe_unused]] jclass clazz) {
|
||||
std::vector<std::string> games;
|
||||
const FileUtil::DirectoryEntryCallable ScanDir =
|
||||
[&games, &ScanDir](u64*, const std::string& directory, const std::string& virtual_name) {
|
||||
std::string path = directory + virtual_name;
|
||||
if (FileUtil::IsDirectory(path)) {
|
||||
path += '/';
|
||||
FileUtil::ForeachDirectoryEntry(nullptr, path, ScanDir);
|
||||
} else {
|
||||
if (!FileUtil::Exists(path))
|
||||
return false;
|
||||
auto loader = Loader::GetLoader(path);
|
||||
if (loader) {
|
||||
bool executable{};
|
||||
const Loader::ResultStatus result = loader->IsExecutable(executable);
|
||||
if (Loader::ResultStatus::Success == result && executable) {
|
||||
games.emplace_back(path);
|
||||
}
|
||||
Service::FS::MediaType media_type;
|
||||
const FileUtil::DirectoryEntryCallable ScanDir = [&games, &ScanDir, &media_type](
|
||||
u64*, const std::string& directory,
|
||||
const std::string& virtual_name) {
|
||||
std::string path = directory + virtual_name;
|
||||
if (FileUtil::IsDirectory(path)) {
|
||||
path += '/';
|
||||
FileUtil::ForeachDirectoryEntry(nullptr, path, ScanDir);
|
||||
} else {
|
||||
if (!FileUtil::Exists(path))
|
||||
return false;
|
||||
auto loader = Loader::GetLoader(path);
|
||||
if (loader) {
|
||||
bool executable{};
|
||||
const Loader::ResultStatus result = loader->IsExecutable(executable);
|
||||
if (Loader::ResultStatus::Success == result && executable) {
|
||||
games.emplace_back(path + "|" + std::to_string(static_cast<int>(media_type)));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
return true;
|
||||
};
|
||||
media_type = Service::FS::MediaType::SDMC;
|
||||
ScanDir(nullptr, "",
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir) +
|
||||
"Nintendo "
|
||||
"3DS/00000000000000000000000000000000/"
|
||||
"00000000000000000000000000000000/title/00040000");
|
||||
media_type = Service::FS::MediaType::NAND;
|
||||
ScanDir(nullptr, "",
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
|
||||
"00000000000000000000000000000000/title/00040010");
|
||||
@ -1108,10 +1112,10 @@ void Java_org_citra_citra_1emu_NativeLibrary_setInsertedCartridge(JNIEnv* env, j
|
||||
}
|
||||
|
||||
jboolean Java_org_citra_citra_1emu_NativeLibrary_uninstallTitle(JNIEnv* env, jobject obj,
|
||||
jlong j_titleid) {
|
||||
const auto titleid = static_cast<long long>(env, j_titleid);
|
||||
// TODO: Don't hard-code to SDMC? (CBA to pass a value from Kotlin at the moment) -OS
|
||||
const auto result = Service::AM::UninstallProgram(Service::FS::MediaType::SDMC, titleid);
|
||||
jlong j_titleid, jint j_mediatype) {
|
||||
const auto titleid = static_cast<u64>(j_titleid);
|
||||
const auto result =
|
||||
Service::AM::UninstallProgram(static_cast<Service::FS::MediaType>(j_mediatype), titleid);
|
||||
if (result.IsError()) {
|
||||
LOG_ERROR(Frontend, "Failed to uninstall '{}': 0x{:08X}", std::to_string(titleid),
|
||||
result.raw);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user