android/GameList: Scan for installed titles

This commit is contained in:
BreadFish64 2020-04-28 12:53:57 -05:00 committed by bunnei
parent 0ea79b55b0
commit 46a639d082
5 changed files with 91 additions and 42 deletions

View File

@ -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();

View File

@ -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();
}

View File

@ -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;

View File

@ -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_);

View File

@ -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);
}