committed by
bunnei
2 changed files with 260 additions and 275 deletions
-
275src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GameDatabase.java
-
260src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GameDatabase.kt
@ -1,275 +0,0 @@ |
|||
package org.yuzu.yuzu_emu.model; |
|||
|
|||
import android.content.ContentValues; |
|||
import android.content.Context; |
|||
import android.database.Cursor; |
|||
import android.database.sqlite.SQLiteDatabase; |
|||
import android.database.sqlite.SQLiteOpenHelper; |
|||
import android.net.Uri; |
|||
|
|||
import org.yuzu.yuzu_emu.NativeLibrary; |
|||
import org.yuzu.yuzu_emu.utils.FileUtil; |
|||
import org.yuzu.yuzu_emu.utils.Log; |
|||
|
|||
import java.io.File; |
|||
import java.util.Arrays; |
|||
import java.util.HashSet; |
|||
import java.util.Set; |
|||
|
|||
import rx.Observable; |
|||
|
|||
/** |
|||
* A helper class that provides several utilities simplifying interaction with |
|||
* the SQLite database. |
|||
*/ |
|||
public final class GameDatabase extends SQLiteOpenHelper { |
|||
public static final int COLUMN_DB_ID = 0; |
|||
public static final int GAME_COLUMN_PATH = 1; |
|||
public static final int GAME_COLUMN_TITLE = 2; |
|||
public static final int GAME_COLUMN_DESCRIPTION = 3; |
|||
public static final int GAME_COLUMN_REGIONS = 4; |
|||
public static final int GAME_COLUMN_GAME_ID = 5; |
|||
public static final int GAME_COLUMN_CAPTION = 6; |
|||
public static final int FOLDER_COLUMN_PATH = 1; |
|||
public static final String KEY_DB_ID = "_id"; |
|||
public static final String KEY_GAME_PATH = "path"; |
|||
public static final String KEY_GAME_TITLE = "title"; |
|||
public static final String KEY_GAME_DESCRIPTION = "description"; |
|||
public static final String KEY_GAME_REGIONS = "regions"; |
|||
public static final String KEY_GAME_ID = "game_id"; |
|||
public static final String KEY_GAME_COMPANY = "company"; |
|||
public static final String KEY_FOLDER_PATH = "path"; |
|||
public static final String TABLE_NAME_FOLDERS = "folders"; |
|||
public static final String TABLE_NAME_GAMES = "games"; |
|||
private static final int DB_VERSION = 2; |
|||
private static final String TYPE_PRIMARY = " INTEGER PRIMARY KEY"; |
|||
private static final String TYPE_INTEGER = " INTEGER"; |
|||
private static final String TYPE_STRING = " TEXT"; |
|||
|
|||
private static final String CONSTRAINT_UNIQUE = " UNIQUE"; |
|||
|
|||
private static final String SEPARATOR = ", "; |
|||
|
|||
private static final String SQL_CREATE_GAMES = "CREATE TABLE " + TABLE_NAME_GAMES + "(" |
|||
+ KEY_DB_ID + TYPE_PRIMARY + SEPARATOR |
|||
+ KEY_GAME_PATH + TYPE_STRING + SEPARATOR |
|||
+ KEY_GAME_TITLE + TYPE_STRING + SEPARATOR |
|||
+ KEY_GAME_DESCRIPTION + TYPE_STRING + SEPARATOR |
|||
+ KEY_GAME_REGIONS + TYPE_STRING + SEPARATOR |
|||
+ KEY_GAME_ID + TYPE_STRING + SEPARATOR |
|||
+ KEY_GAME_COMPANY + TYPE_STRING + ")"; |
|||
|
|||
private static final String SQL_CREATE_FOLDERS = "CREATE TABLE " + TABLE_NAME_FOLDERS + "(" |
|||
+ KEY_DB_ID + TYPE_PRIMARY + SEPARATOR |
|||
+ KEY_FOLDER_PATH + TYPE_STRING + CONSTRAINT_UNIQUE + ")"; |
|||
|
|||
private static final String SQL_DELETE_FOLDERS = "DROP TABLE IF EXISTS " + TABLE_NAME_FOLDERS; |
|||
private static final String SQL_DELETE_GAMES = "DROP TABLE IF EXISTS " + TABLE_NAME_GAMES; |
|||
private final Context context; |
|||
|
|||
public GameDatabase(Context context) { |
|||
// Superclass constructor builds a database or uses an existing one. |
|||
super(context, "games.db", null, DB_VERSION); |
|||
this.context = context; |
|||
} |
|||
|
|||
@Override |
|||
public void onCreate(SQLiteDatabase database) { |
|||
Log.debug("[GameDatabase] GameDatabase - Creating database..."); |
|||
|
|||
execSqlAndLog(database, SQL_CREATE_GAMES); |
|||
execSqlAndLog(database, SQL_CREATE_FOLDERS); |
|||
} |
|||
|
|||
@Override |
|||
public void onDowngrade(SQLiteDatabase database, int oldVersion, int newVersion) { |
|||
Log.verbose("[GameDatabase] Downgrades not supporting, clearing databases.."); |
|||
execSqlAndLog(database, SQL_DELETE_FOLDERS); |
|||
execSqlAndLog(database, SQL_CREATE_FOLDERS); |
|||
|
|||
execSqlAndLog(database, SQL_DELETE_GAMES); |
|||
execSqlAndLog(database, SQL_CREATE_GAMES); |
|||
} |
|||
|
|||
@Override |
|||
public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) { |
|||
Log.info("[GameDatabase] Upgrading database from schema version " + oldVersion + " to " + |
|||
newVersion); |
|||
|
|||
// Delete all the games |
|||
execSqlAndLog(database, SQL_DELETE_GAMES); |
|||
execSqlAndLog(database, SQL_CREATE_GAMES); |
|||
} |
|||
|
|||
public void resetDatabase(SQLiteDatabase database) { |
|||
execSqlAndLog(database, SQL_DELETE_FOLDERS); |
|||
execSqlAndLog(database, SQL_CREATE_FOLDERS); |
|||
|
|||
execSqlAndLog(database, SQL_DELETE_GAMES); |
|||
execSqlAndLog(database, SQL_CREATE_GAMES); |
|||
} |
|||
|
|||
public void scanLibrary(SQLiteDatabase database) { |
|||
// Before scanning known folders, go through the game table and remove any entries for which the file itself is missing. |
|||
Cursor fileCursor = database.query(TABLE_NAME_GAMES, |
|||
null, // Get all columns. |
|||
null, // Get all rows. |
|||
null, |
|||
null, // No grouping. |
|||
null, |
|||
null); // Order of games is irrelevant. |
|||
|
|||
// Possibly overly defensive, but ensures that moveToNext() does not skip a row. |
|||
fileCursor.moveToPosition(-1); |
|||
|
|||
while (fileCursor.moveToNext()) { |
|||
String gamePath = fileCursor.getString(GAME_COLUMN_PATH); |
|||
File game = new File(gamePath); |
|||
|
|||
if (!game.exists()) { |
|||
database.delete(TABLE_NAME_GAMES, |
|||
KEY_DB_ID + " = ?", |
|||
new String[]{Long.toString(fileCursor.getLong(COLUMN_DB_ID))}); |
|||
} |
|||
} |
|||
|
|||
// Get a cursor listing all the folders the user has added to the library. |
|||
Cursor folderCursor = database.query(TABLE_NAME_FOLDERS, |
|||
null, // Get all columns. |
|||
null, // Get all rows. |
|||
null, |
|||
null, // No grouping. |
|||
null, |
|||
null); // Order of folders is irrelevant. |
|||
|
|||
Set<String> allowedExtensions = new HashSet<String>(Arrays.asList( |
|||
".xci", ".nsp", ".nca", ".nro")); |
|||
|
|||
// Possibly overly defensive, but ensures that moveToNext() does not skip a row. |
|||
folderCursor.moveToPosition(-1); |
|||
|
|||
// 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); |
|||
|
|||
Uri folderUri = Uri.parse(folderPath); |
|||
// If the folder is empty because it no longer exists, remove it from the library. |
|||
if (FileUtil.listFiles(context, folderUri).length == 0) { |
|||
Log.error( |
|||
"[GameDatabase] Folder no longer exists. Removing from the library: " + folderPath); |
|||
database.delete(TABLE_NAME_FOLDERS, |
|||
KEY_DB_ID + " = ?", |
|||
new String[]{Long.toString(folderCursor.getLong(COLUMN_DB_ID))}); |
|||
} |
|||
|
|||
this.addGamesRecursive(database, folderUri, allowedExtensions, 3); |
|||
} |
|||
|
|||
fileCursor.close(); |
|||
folderCursor.close(); |
|||
|
|||
database.close(); |
|||
} |
|||
|
|||
private void addGamesRecursive(SQLiteDatabase database, Uri parent, Set<String> allowedExtensions, int depth) { |
|||
if (depth <= 0) { |
|||
return; |
|||
} |
|||
|
|||
// Ensure keys are loaded so that ROM metadata can be decrypted. |
|||
NativeLibrary.ReloadKeys(); |
|||
|
|||
MinimalDocumentFile[] children = FileUtil.listFiles(context, parent); |
|||
for (MinimalDocumentFile file : children) { |
|||
if (file.isDirectory()) { |
|||
Set<String> newExtensions = new HashSet<>(Arrays.asList( |
|||
".xci", ".nsp", ".nca", ".nro")); |
|||
this.addGamesRecursive(database, file.getUri(), newExtensions, depth - 1); |
|||
} else { |
|||
String filename = file.getUri().toString(); |
|||
|
|||
int extensionStart = filename.lastIndexOf('.'); |
|||
if (extensionStart > 0) { |
|||
String fileExtension = filename.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(database, filename); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
private static void attemptToAddGame(SQLiteDatabase database, String 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)); |
|||
} |
|||
} |
|||
|
|||
public Observable<Cursor> getGames() { |
|||
return Observable.create(subscriber -> |
|||
{ |
|||
Log.info("[GameDatabase] Reading games list..."); |
|||
|
|||
SQLiteDatabase database = getReadableDatabase(); |
|||
Cursor resultCursor = database.query( |
|||
TABLE_NAME_GAMES, |
|||
null, |
|||
null, |
|||
null, |
|||
null, |
|||
null, |
|||
KEY_GAME_TITLE + " ASC" |
|||
); |
|||
|
|||
// Pass the result cursor to the consumer. |
|||
subscriber.onNext(resultCursor); |
|||
|
|||
// Tell the consumer we're done; it will unsubscribe implicitly. |
|||
subscriber.onCompleted(); |
|||
}); |
|||
} |
|||
|
|||
private void execSqlAndLog(SQLiteDatabase database, String sql) { |
|||
Log.verbose("[GameDatabase] Executing SQL: " + sql); |
|||
database.execSQL(sql); |
|||
} |
|||
} |
|||
@ -0,0 +1,260 @@ |
|||
package org.yuzu.yuzu_emu.model |
|||
|
|||
import android.content.Context |
|||
import android.database.Cursor |
|||
import android.database.sqlite.SQLiteDatabase |
|||
import android.database.sqlite.SQLiteOpenHelper |
|||
import android.net.Uri |
|||
import org.yuzu.yuzu_emu.NativeLibrary |
|||
import org.yuzu.yuzu_emu.utils.FileUtil |
|||
import org.yuzu.yuzu_emu.utils.Log |
|||
import rx.Observable |
|||
import rx.Subscriber |
|||
import java.io.File |
|||
import java.util.* |
|||
|
|||
/** |
|||
* A helper class that provides several utilities simplifying interaction with |
|||
* the SQLite database. |
|||
*/ |
|||
class GameDatabase(private val context: Context) : |
|||
SQLiteOpenHelper(context, "games.db", null, DB_VERSION) { |
|||
override fun onCreate(database: SQLiteDatabase) { |
|||
Log.debug("[GameDatabase] GameDatabase - Creating database...") |
|||
execSqlAndLog(database, SQL_CREATE_GAMES) |
|||
execSqlAndLog(database, SQL_CREATE_FOLDERS) |
|||
} |
|||
|
|||
override fun onDowngrade(database: SQLiteDatabase, oldVersion: Int, newVersion: Int) { |
|||
Log.verbose("[GameDatabase] Downgrades not supporting, clearing databases..") |
|||
execSqlAndLog(database, SQL_DELETE_FOLDERS) |
|||
execSqlAndLog(database, SQL_CREATE_FOLDERS) |
|||
execSqlAndLog(database, SQL_DELETE_GAMES) |
|||
execSqlAndLog(database, SQL_CREATE_GAMES) |
|||
} |
|||
|
|||
override fun onUpgrade(database: SQLiteDatabase, oldVersion: Int, newVersion: Int) { |
|||
Log.info( |
|||
"[GameDatabase] Upgrading database from schema version $oldVersion to $newVersion" |
|||
) |
|||
|
|||
// Delete all the games |
|||
execSqlAndLog(database, SQL_DELETE_GAMES) |
|||
execSqlAndLog(database, SQL_CREATE_GAMES) |
|||
} |
|||
|
|||
fun resetDatabase(database: SQLiteDatabase) { |
|||
execSqlAndLog(database, SQL_DELETE_FOLDERS) |
|||
execSqlAndLog(database, SQL_CREATE_FOLDERS) |
|||
execSqlAndLog(database, SQL_DELETE_GAMES) |
|||
execSqlAndLog(database, SQL_CREATE_GAMES) |
|||
} |
|||
|
|||
fun scanLibrary(database: SQLiteDatabase) { |
|||
// Before scanning known folders, go through the game table and remove any entries for which the file itself is missing. |
|||
val fileCursor = database.query( |
|||
TABLE_NAME_GAMES, |
|||
null, // Get all columns. |
|||
null, // Get all rows. |
|||
null, |
|||
null, // No grouping. |
|||
null, |
|||
null |
|||
) // Order of games is irrelevant. |
|||
|
|||
// Possibly overly defensive, but ensures that moveToNext() does not skip a row. |
|||
fileCursor.moveToPosition(-1) |
|||
while (fileCursor.moveToNext()) { |
|||
val gamePath = fileCursor.getString(GAME_COLUMN_PATH) |
|||
val game = File(gamePath) |
|||
if (!game.exists()) { |
|||
database.delete( |
|||
TABLE_NAME_GAMES, |
|||
"$KEY_DB_ID = ?", |
|||
arrayOf(fileCursor.getLong(COLUMN_DB_ID).toString()) |
|||
) |
|||
} |
|||
} |
|||
|
|||
// Get a cursor listing all the folders the user has added to the library. |
|||
val folderCursor = database.query( |
|||
TABLE_NAME_FOLDERS, |
|||
null, // Get all columns. |
|||
null, // Get all rows. |
|||
null, |
|||
null, // No grouping. |
|||
null, |
|||
null |
|||
) // Order of folders is irrelevant. |
|||
|
|||
|
|||
// Possibly overly defensive, but ensures that moveToNext() does not skip a row. |
|||
folderCursor.moveToPosition(-1) |
|||
|
|||
// Iterate through all results of the DB query (i.e. all folders in the library.) |
|||
while (folderCursor.moveToNext()) { |
|||
val folderPath = folderCursor.getString(FOLDER_COLUMN_PATH) |
|||
val folderUri = Uri.parse(folderPath) |
|||
// If the folder is empty because it no longer exists, remove it from the library. |
|||
if (FileUtil.listFiles(context, folderUri).isEmpty()) { |
|||
Log.error( |
|||
"[GameDatabase] Folder no longer exists. Removing from the library: $folderPath" |
|||
) |
|||
database.delete( |
|||
TABLE_NAME_FOLDERS, |
|||
"$KEY_DB_ID = ?", |
|||
arrayOf(folderCursor.getLong(COLUMN_DB_ID).toString()) |
|||
) |
|||
} |
|||
addGamesRecursive(database, folderUri, Game.extensions, 3) |
|||
} |
|||
fileCursor.close() |
|||
folderCursor.close() |
|||
database.close() |
|||
} |
|||
|
|||
private fun addGamesRecursive( |
|||
database: SQLiteDatabase, |
|||
parent: Uri, |
|||
allowedExtensions: Set<String>, |
|||
depth: Int |
|||
) { |
|||
if (depth <= 0) |
|||
return |
|||
|
|||
// Ensure keys are loaded so that ROM metadata can be decrypted. |
|||
NativeLibrary.ReloadKeys() |
|||
val children = FileUtil.listFiles(context, parent) |
|||
for (file in children) { |
|||
if (file.isDirectory) { |
|||
addGamesRecursive(database, file.uri, Game.extensions, depth - 1) |
|||
} else { |
|||
val filename = file.uri.toString() |
|||
val extensionStart = filename.lastIndexOf('.') |
|||
if (extensionStart > 0) { |
|||
val fileExtension = filename.substring(extensionStart) |
|||
|
|||
// Check that the file has an extension we care about before trying to read out of it. |
|||
if (allowedExtensions.contains(fileExtension.lowercase(Locale.getDefault()))) { |
|||
attemptToAddGame(database, filename) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
// Pass the result cursor to the consumer. |
|||
|
|||
// Tell the consumer we're done; it will unsubscribe implicitly. |
|||
val games: Observable<Cursor?> |
|||
get() = Observable.create { subscriber: Subscriber<in Cursor?> -> |
|||
Log.info("[GameDatabase] Reading games list...") |
|||
val database = readableDatabase |
|||
val resultCursor = database.query( |
|||
TABLE_NAME_GAMES, |
|||
null, |
|||
null, |
|||
null, |
|||
null, |
|||
null, |
|||
"$KEY_GAME_TITLE ASC" |
|||
) |
|||
|
|||
// Pass the result cursor to the consumer. |
|||
subscriber.onNext(resultCursor) |
|||
|
|||
// Tell the consumer we're done; it will unsubscribe implicitly. |
|||
subscriber.onCompleted() |
|||
} |
|||
|
|||
private fun execSqlAndLog(database: SQLiteDatabase, sql: String) { |
|||
Log.verbose("[GameDatabase] Executing SQL: $sql") |
|||
database.execSQL(sql) |
|||
} |
|||
|
|||
companion object { |
|||
const val COLUMN_DB_ID = 0 |
|||
const val GAME_COLUMN_PATH = 1 |
|||
const val GAME_COLUMN_TITLE = 2 |
|||
const val GAME_COLUMN_DESCRIPTION = 3 |
|||
const val GAME_COLUMN_REGIONS = 4 |
|||
const val GAME_COLUMN_GAME_ID = 5 |
|||
const val GAME_COLUMN_CAPTION = 6 |
|||
const val FOLDER_COLUMN_PATH = 1 |
|||
const val KEY_DB_ID = "_id" |
|||
const val KEY_GAME_PATH = "path" |
|||
const val KEY_GAME_TITLE = "title" |
|||
const val KEY_GAME_DESCRIPTION = "description" |
|||
const val KEY_GAME_REGIONS = "regions" |
|||
const val KEY_GAME_ID = "game_id" |
|||
const val KEY_GAME_COMPANY = "company" |
|||
const val KEY_FOLDER_PATH = "path" |
|||
const val TABLE_NAME_FOLDERS = "folders" |
|||
const val TABLE_NAME_GAMES = "games" |
|||
private const val DB_VERSION = 2 |
|||
private const val TYPE_PRIMARY = " INTEGER PRIMARY KEY" |
|||
private const val TYPE_INTEGER = " INTEGER" |
|||
private const val TYPE_STRING = " TEXT" |
|||
private const val CONSTRAINT_UNIQUE = " UNIQUE" |
|||
private const val SEPARATOR = ", " |
|||
private const val SQL_CREATE_GAMES = ("CREATE TABLE " + TABLE_NAME_GAMES + "(" |
|||
+ KEY_DB_ID + TYPE_PRIMARY + SEPARATOR |
|||
+ KEY_GAME_PATH + TYPE_STRING + SEPARATOR |
|||
+ KEY_GAME_TITLE + TYPE_STRING + SEPARATOR |
|||
+ KEY_GAME_DESCRIPTION + TYPE_STRING + SEPARATOR |
|||
+ KEY_GAME_REGIONS + TYPE_STRING + SEPARATOR |
|||
+ KEY_GAME_ID + TYPE_STRING + SEPARATOR |
|||
+ KEY_GAME_COMPANY + TYPE_STRING + ")") |
|||
private const val SQL_CREATE_FOLDERS = ("CREATE TABLE " + TABLE_NAME_FOLDERS + "(" |
|||
+ KEY_DB_ID + TYPE_PRIMARY + SEPARATOR |
|||
+ KEY_FOLDER_PATH + TYPE_STRING + CONSTRAINT_UNIQUE + ")") |
|||
private const val SQL_DELETE_FOLDERS = "DROP TABLE IF EXISTS $TABLE_NAME_FOLDERS" |
|||
private const val SQL_DELETE_GAMES = "DROP TABLE IF EXISTS $TABLE_NAME_GAMES" |
|||
private fun attemptToAddGame(database: SQLiteDatabase, filePath: String) { |
|||
var name = NativeLibrary.GetTitle(filePath) |
|||
|
|||
// If the game's title field is empty, use the filename. |
|||
if (name.isEmpty()) { |
|||
name = filePath.substring(filePath.lastIndexOf("/") + 1) |
|||
} |
|||
var 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(".") |
|||
) |
|||
} |
|||
val game = Game.asContentValues( |
|||
name, |
|||
NativeLibrary.GetDescription(filePath).replace("\n", " "), |
|||
NativeLibrary.GetRegions(filePath), |
|||
filePath, |
|||
gameId, |
|||
NativeLibrary.GetCompany(filePath) |
|||
) |
|||
|
|||
// Try to update an existing game first. |
|||
val rowsMatched = database.update( |
|||
TABLE_NAME_GAMES, // Which table to update. |
|||
game, // The values to fill the row with. |
|||
"$KEY_GAME_ID = ?", arrayOf( |
|||
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)) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue