android/GameList: Scan for installed titles

This commit is contained in:
BreadFish64 2020-04-28 12:53:57 -05:00 committed by bunnei
parent acfcecb0ee
commit 2b815d0464
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 void SetUserDirectory(String directory);
public static native String[] GetInstalledGamePaths();
// Create the config.ini file. // Create the config.ini file.
public static native void CreateConfigFile(); public static native void CreateConfigFile();

View File

@ -13,6 +13,7 @@ import java.io.File;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.function.Consumer;
import rx.Observable; import rx.Observable;
@ -147,27 +148,7 @@ public final class GameDatabase extends SQLiteOpenHelper {
// Possibly overly defensive, but ensures that moveToNext() does not skip a row. // Possibly overly defensive, but ensures that moveToNext() does not skip a row.
folderCursor.moveToPosition(-1); folderCursor.moveToPosition(-1);
// Iterate through all results of the DB query (i.e. all folders in the library.) Consumer<String> AttemptToAddGame = filePath -> {
while (folderCursor.moveToNext()) {
String folderPath = folderCursor.getString(FOLDER_COLUMN_PATH);
File folder = new File(folderPath);
Log.info("[GameDatabase] Reading files from library folder: " + folderPath);
// Iterate through every file in the folder.
File[] children = folder.listFiles();
if (children != null) {
for (File file : children) {
if (!file.isHidden() && !file.isDirectory()) {
String filePath = file.getPath();
int extensionStart = filePath.lastIndexOf('.');
if (extensionStart > 0) {
String fileExtension = filePath.substring(extensionStart);
// 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); String name = NativeLibrary.GetTitle(filePath);
// If the game's title field is empty, use the filename. // If the game's title field is empty, use the filename.
@ -208,6 +189,30 @@ public final class GameDatabase extends SQLiteOpenHelper {
} else { } else {
Log.verbose("[GameDatabase] Updated game: " + game.getAsString(KEY_GAME_TITLE)); 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);
File folder = new File(folderPath);
Log.info("[GameDatabase] Reading files from library folder: " + folderPath);
// Iterate through every file in the folder.
File[] children = folder.listFiles();
if (children != null) {
for (File file : children) {
if (!file.isHidden() && !file.isDirectory()) {
String filePath = file.getPath();
int extensionStart = filePath.lastIndexOf('.');
if (extensionStart > 0) {
String fileExtension = filePath.substring(extensionStart);
// Check that the file has an extension we care about before trying to read out of it.
if (allowedExtensions.contains(fileExtension.toLowerCase())) {
AttemptToAddGame.accept(filePath);
} }
} }
} }
@ -227,6 +232,8 @@ public final class GameDatabase extends SQLiteOpenHelper {
fileCursor.close(); fileCursor.close();
folderCursor.close(); folderCursor.close();
Arrays.stream(NativeLibrary.GetInstalledGamePaths()).forEach(AttemptToAddGame);
database.close(); database.close();
} }

View File

@ -221,6 +221,43 @@ void Java_org_citra_citra_1emu_NativeLibrary_SetUserDirectory(JNIEnv* env,
FileUtil::SetCurrentDir(GetJString(env, j_directory)); 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, void Java_org_citra_citra_1emu_NativeLibrary_UnPauseEmulation(JNIEnv* env,
[[maybe_unused]] jclass clazz) { [[maybe_unused]] jclass clazz) {
pause_emulation = false; 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( JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_SetUserDirectory(
JNIEnv* env, jclass clazz, jstring j_directory); 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( JNIEXPORT void JNICALL Java_org_citra_citra_1emu_utils_DirectoryInitialization_SetSysDirectory(
JNIEnv* env, jclass clazz, jstring path_); 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::ConfigDir, user_path + CONFIG_DIR DIR_SEP);
g_paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP); g_paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP);
#elif ANDROID #elif ANDROID
if (FileUtil::Exists(ROOT_DIR DIR_SEP SDCARD_DIR)) { if (FileUtil::Exists(DIR_SEP SDCARD_DIR)) {
user_path = ROOT_DIR DIR_SEP SDCARD_DIR DIR_SEP EMU_DATA_DIR DIR_SEP; 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::ConfigDir, user_path + CONFIG_DIR DIR_SEP);
g_paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP); g_paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP);
} }