android/GameList: Scan for installed titles
This commit is contained in:
parent
0ea79b55b0
commit
46a639d082
@ -146,6 +146,8 @@ public final class NativeLibrary {
|
||||
*/
|
||||
public static native void SetUserDirectory(String directory);
|
||||
|
||||
public static native String[] GetInstalledGamePaths();
|
||||
|
||||
// Create the config.ini file.
|
||||
public static native void CreateConfigFile();
|
||||
|
||||
|
@ -13,6 +13,7 @@ import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import rx.Observable;
|
||||
|
||||
@ -147,6 +148,49 @@ public final class GameDatabase extends SQLiteOpenHelper {
|
||||
// Possibly overly defensive, but ensures that moveToNext() does not skip a row.
|
||||
folderCursor.moveToPosition(-1);
|
||||
|
||||
Consumer<String> AttemptToAddGame = filePath -> {
|
||||
String name = NativeLibrary.GetTitle(filePath);
|
||||
|
||||
// If the game's title field is empty, use the filename.
|
||||
if (name.isEmpty()) {
|
||||
name = filePath.substring(filePath.lastIndexOf("/") + 1);
|
||||
}
|
||||
|
||||
String gameId = NativeLibrary.GetGameId(filePath);
|
||||
|
||||
// If the game's ID field is empty, use the filename without extension.
|
||||
if (gameId.isEmpty()) {
|
||||
gameId = filePath.substring(filePath.lastIndexOf("/") + 1,
|
||||
filePath.lastIndexOf("."));
|
||||
}
|
||||
|
||||
ContentValues game = Game.asContentValues(name,
|
||||
NativeLibrary.GetDescription(filePath).replace("\n", " "),
|
||||
NativeLibrary.GetRegions(filePath),
|
||||
filePath,
|
||||
gameId,
|
||||
NativeLibrary.GetCompany(filePath));
|
||||
|
||||
// Try to update an existing game first.
|
||||
int rowsMatched = database.update(TABLE_NAME_GAMES, // Which table to update.
|
||||
game,
|
||||
// The values to fill the row with.
|
||||
KEY_GAME_ID + " = ?",
|
||||
// The WHERE clause used to find the right row.
|
||||
new String[]{game.getAsString(
|
||||
KEY_GAME_ID)}); // The ? in WHERE clause is replaced with this,
|
||||
// which is provided as an array because there
|
||||
// could potentially be more than one argument.
|
||||
|
||||
// If update fails, insert a new game instead.
|
||||
if (rowsMatched == 0) {
|
||||
Log.verbose("[GameDatabase] Adding game: " + game.getAsString(KEY_GAME_TITLE));
|
||||
database.insert(TABLE_NAME_GAMES, null, game);
|
||||
} else {
|
||||
Log.verbose("[GameDatabase] Updated game: " + game.getAsString(KEY_GAME_TITLE));
|
||||
}
|
||||
};
|
||||
|
||||
// Iterate through all results of the DB query (i.e. all folders in the library.)
|
||||
while (folderCursor.moveToNext()) {
|
||||
String folderPath = folderCursor.getString(FOLDER_COLUMN_PATH);
|
||||
@ -168,46 +212,7 @@ public final class GameDatabase extends SQLiteOpenHelper {
|
||||
|
||||
// Check that the file has an extension we care about before trying to read out of it.
|
||||
if (allowedExtensions.contains(fileExtension.toLowerCase())) {
|
||||
String name = NativeLibrary.GetTitle(filePath);
|
||||
|
||||
// If the game's title field is empty, use the filename.
|
||||
if (name.isEmpty()) {
|
||||
name = filePath.substring(filePath.lastIndexOf("/") + 1);
|
||||
}
|
||||
|
||||
String gameId = NativeLibrary.GetGameId(filePath);
|
||||
|
||||
// If the game's ID field is empty, use the filename without extension.
|
||||
if (gameId.isEmpty()) {
|
||||
gameId = filePath.substring(filePath.lastIndexOf("/") + 1,
|
||||
filePath.lastIndexOf("."));
|
||||
}
|
||||
|
||||
ContentValues game = Game.asContentValues(name,
|
||||
NativeLibrary.GetDescription(filePath).replace("\n", " "),
|
||||
NativeLibrary.GetRegions(filePath),
|
||||
filePath,
|
||||
gameId,
|
||||
NativeLibrary.GetCompany(filePath));
|
||||
|
||||
// Try to update an existing game first.
|
||||
int rowsMatched = database.update(TABLE_NAME_GAMES, // Which table to update.
|
||||
game,
|
||||
// The values to fill the row with.
|
||||
KEY_GAME_ID + " = ?",
|
||||
// The WHERE clause used to find the right row.
|
||||
new String[]{game.getAsString(
|
||||
KEY_GAME_ID)}); // The ? in WHERE clause is replaced with this,
|
||||
// which is provided as an array because there
|
||||
// could potentially be more than one argument.
|
||||
|
||||
// If update fails, insert a new game instead.
|
||||
if (rowsMatched == 0) {
|
||||
Log.verbose("[GameDatabase] Adding game: " + game.getAsString(KEY_GAME_TITLE));
|
||||
database.insert(TABLE_NAME_GAMES, null, game);
|
||||
} else {
|
||||
Log.verbose("[GameDatabase] Updated game: " + game.getAsString(KEY_GAME_TITLE));
|
||||
}
|
||||
AttemptToAddGame.accept(filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -227,6 +232,8 @@ public final class GameDatabase extends SQLiteOpenHelper {
|
||||
|
||||
fileCursor.close();
|
||||
folderCursor.close();
|
||||
|
||||
Arrays.stream(NativeLibrary.GetInstalledGamePaths()).forEach(AttemptToAddGame);
|
||||
database.close();
|
||||
}
|
||||
|
||||
|
@ -221,6 +221,43 @@ void Java_org_citra_citra_1emu_NativeLibrary_SetUserDirectory(JNIEnv* env,
|
||||
FileUtil::SetCurrentDir(GetJString(env, j_directory));
|
||||
}
|
||||
|
||||
jobjectArray Java_org_citra_citra_1emu_NativeLibrary_GetInstalledGamePaths(
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
ScanDir(nullptr, "",
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir) +
|
||||
"Nintendo "
|
||||
"3DS/00000000000000000000000000000000/"
|
||||
"00000000000000000000000000000000/title/00040000");
|
||||
ScanDir(nullptr, "",
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
|
||||
"00000000000000000000000000000000/title/00040010");
|
||||
jobjectArray jgames =
|
||||
env->NewObjectArray(static_cast<jsize>(games.size()), env->FindClass("java/lang/String"),
|
||||
nullptr);
|
||||
for (jsize i = 0; i < games.size(); ++i)
|
||||
env->SetObjectArrayElement(jgames, i, env->NewStringUTF(games[i].c_str()));
|
||||
return jgames;
|
||||
}
|
||||
|
||||
void Java_org_citra_citra_1emu_NativeLibrary_UnPauseEmulation(JNIEnv* env,
|
||||
[[maybe_unused]] jclass clazz) {
|
||||
pause_emulation = false;
|
||||
|
@ -70,6 +70,9 @@ JNIEXPORT jstring JNICALL Java_org_citra_citra_1emu_NativeLibrary_GetGitRevision
|
||||
JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_SetUserDirectory(
|
||||
JNIEnv* env, jclass clazz, jstring j_directory);
|
||||
|
||||
JNIEXPORT jobjectArray JNICALL
|
||||
Java_org_citra_citra_1emu_NativeLibrary_GetInstalledGamePaths(JNIEnv* env, jclass clazz);
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_citra_citra_1emu_utils_DirectoryInitialization_SetSysDirectory(
|
||||
JNIEnv* env, jclass clazz, jstring path_);
|
||||
|
||||
|
@ -695,8 +695,8 @@ void SetUserPath(const std::string& path) {
|
||||
g_paths.emplace(UserPath::ConfigDir, user_path + CONFIG_DIR DIR_SEP);
|
||||
g_paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP);
|
||||
#elif ANDROID
|
||||
if (FileUtil::Exists(ROOT_DIR DIR_SEP SDCARD_DIR)) {
|
||||
user_path = ROOT_DIR DIR_SEP SDCARD_DIR DIR_SEP EMU_DATA_DIR DIR_SEP;
|
||||
if (FileUtil::Exists(DIR_SEP SDCARD_DIR)) {
|
||||
user_path = DIR_SEP SDCARD_DIR DIR_SEP EMU_DATA_DIR DIR_SEP;
|
||||
g_paths.emplace(UserPath::ConfigDir, user_path + CONFIG_DIR DIR_SEP);
|
||||
g_paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user