From be35d875b2f7a31c77573836e24064295a966173 Mon Sep 17 00:00:00 2001 From: Andy2 Date: Wed, 24 Nov 2010 17:22:04 -0800 Subject: [PATCH] move game data from separate files into a BLOB column in the existing summaries db table, using the existing SNAPSHOT column rather than adding a new one and upping the version. Includes utility fired at game-start to convert existing games that seems to work. Also improved a few queries and updates to -- I think -- use the API better. --- .../src/org/eehouse/android/xw4/DBUtils.java | 112 +++++++++++++++--- .../eehouse/android/xw4/GameConverter.java | 81 +++++++++++++ .../eehouse/android/xw4/GameListAdapter.java | 6 +- .../org/eehouse/android/xw4/GameUtils.java | 57 +++------ .../org/eehouse/android/xw4/GamesList.java | 10 +- 5 files changed, 203 insertions(+), 63 deletions(-) create mode 100644 xwords4/android/XWords4/src/org/eehouse/android/xw4/GameConverter.java diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java index 6f63ab097..a5b2aaaaf 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java @@ -150,7 +150,6 @@ public class DBUtils { db.delete( DBHelper.TABLE_NAME_SUM, selection, null ); } else { ContentValues values = new ContentValues(); - values.put( DBHelper.FILE_NAME, path ); values.put( DBHelper.NUM_MOVES, summary.nMoves ); values.put( DBHelper.NUM_PLAYERS, summary.nPlayers ); values.put( DBHelper.PLAYERS, @@ -158,6 +157,7 @@ public class DBUtils { values.put( DBHelper.DICTLANG, summary.dictLang ); values.put( DBHelper.DICTNAME, summary.dictName ); values.put( DBHelper.GAME_OVER, summary.gameOver ); + values.put( DBHelper.HASMSGS, 0 ); if ( null != summary.scores ) { StringBuffer sb = new StringBuffer(); @@ -178,16 +178,14 @@ public class DBUtils { Utils.logf( "saveSummary: nMoves=%d", summary.nMoves ); - try { - long result = db.replaceOrThrow( DBHelper.TABLE_NAME_SUM, - "", values ); - } catch ( Exception ex ) { - Utils.logf( "ex: %s", ex.toString() ); - } + String selection = DBHelper.FILE_NAME + "=\"" + path + "\""; + long result = db.update( DBHelper.TABLE_NAME_SUM, + values, selection, null ); + Assert.assertTrue( result >= 0 ); } db.close(); } - } + } // saveSummary public static int countGamesUsing( Context context, String dict ) { @@ -213,12 +211,14 @@ public class DBUtils { { synchronized( s_dbHelper ) { SQLiteDatabase db = s_dbHelper.getWritableDatabase(); - - String cmd = String.format( "UPDATE %s SET %s = 1 WHERE %s = '%s'", - DBHelper.TABLE_NAME_SUM, - DBHelper.HASMSGS, - DBHelper.RELAYID, relayID ); - db.execSQL( cmd ); + + String selection = DBHelper.RELAYID + "=\'" + relayID + "\'"; + ContentValues values = new ContentValues(); + values.put( DBHelper.HASMSGS, 1 ); + + int result = db.update( DBHelper.TABLE_NAME_SUM, + values, selection, null ); + Assert.assertTrue( result == 1 ); db.close(); } } @@ -356,6 +356,90 @@ public class DBUtils { } } + public static void saveGame( Context context, String path, byte[] bytes ) + { + initDB( context ); + synchronized( s_dbHelper ) { + SQLiteDatabase db = s_dbHelper.getWritableDatabase(); + + String selection = DBHelper.FILE_NAME + "=\"" + path + "\""; + ContentValues values = new ContentValues(); + values.put( DBHelper.SNAPSHOT, bytes ); + + int result = db.update( DBHelper.TABLE_NAME_SUM, + values, selection, null ); + if ( 0 == result ) { + values.put( DBHelper.FILE_NAME, path ); + long row = db.insert( DBHelper.TABLE_NAME_SUM, null, values ); + Assert.assertTrue( row >= 0 ); + } + db.close(); + } + } + + public static byte[] loadGame( Context context, String path ) + { + Assert.assertNotNull( path ); + byte[] result = null; + initDB( context ); + synchronized( s_dbHelper ) { + SQLiteDatabase db = s_dbHelper.getReadableDatabase(); + + String[] columns = { DBHelper.SNAPSHOT }; + String selection = DBHelper.FILE_NAME + "=\"" + path + "\""; + Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns, + selection, null, null, null, null ); + if ( 1 == cursor.getCount() && cursor.moveToFirst() ) { + result = cursor.getBlob( cursor + .getColumnIndex(DBHelper.SNAPSHOT)); + } + cursor.close(); + db.close(); + } + return result; + } + + public static void deleteGame( Context context, String path ) + { + initDB( context ); + synchronized( s_dbHelper ) { + SQLiteDatabase db = s_dbHelper.getWritableDatabase(); + String selection = DBHelper.FILE_NAME + "=\"" + path + "\""; + db.delete( DBHelper.TABLE_NAME_SUM, selection, null ); + db.close(); + } + } + + public static String[] gamesList( Context context ) + { + ArrayList al = new ArrayList(); + + initDB( context ); + synchronized( s_dbHelper ) { + SQLiteDatabase db = s_dbHelper.getReadableDatabase(); + + String[] columns = { DBHelper.FILE_NAME }; + Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns, + null, null, null, null, null ); + if ( 0 < cursor.getCount() ) { + cursor.moveToFirst(); + for ( ; ; ) { + int index = cursor.getColumnIndex( DBHelper.FILE_NAME ); + String name = cursor.getString( index ); + al.add( cursor.getString( index ) ); + if ( cursor.isLast() ) { + break; + } + cursor.moveToNext(); + } + } + cursor.close(); + db.close(); + } + + return al.toArray( new String[al.size()] ); + } + private static void initDB( Context context ) { if ( null == s_dbHelper ) { diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameConverter.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameConverter.java new file mode 100644 index 000000000..e522de498 --- /dev/null +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameConverter.java @@ -0,0 +1,81 @@ +/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* + * Copyright 2010 by Eric House (xwords@eehouse.org). All rights + * reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package org.eehouse.android.xw4; + +import android.content.Context; +import java.io.FileInputStream; +import java.util.ArrayList; + +// Rip this out a month or so after releasing... +public class GameConverter { + + public static void convert( Context context ) + { + String[] games = gamesList( context ); + if ( null == games ) { + Utils.logf( "GameConverter::convert() no old games found" ); + } else { + for ( String game : games ) { + Utils.logf( "GameConverter::convert() converting %s", + game ); + byte[] bytes = savedGame( context, game ); + DBUtils.saveGame( context, game, bytes ); + context.deleteFile( game ); + } + } + } + + private static byte[] savedGame( Context context, String path ) + { + byte[] stream = null; + try { + FileInputStream in = context.openFileInput( path ); + int len = in.available(); + stream = new byte[len]; + in.read( stream, 0, len ); + in.close(); + } catch ( java.io.FileNotFoundException fnf ) { + Utils.logf( fnf.toString() ); + stream = null; + } catch ( java.io.IOException io ) { + Utils.logf( io.toString() ); + stream = null; + } + return stream; + } + + private static String[] gamesList( Context context ) + { + ArrayList al = new ArrayList(); + for ( String file : context.fileList() ) { + if ( file.endsWith( XWConstants.GAME_EXTN ) ) { + al.add( file ); + } + } + + int siz = al.size(); + String[] result = null; + if ( siz > 0 ) { + result = al.toArray( new String[siz] ); + } + return result; + } +} diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java index 1cb56c9c2..1dd44cbdf 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java @@ -41,7 +41,7 @@ public class GameListAdapter extends XWListAdapter { private HashMap m_viewsCache; public GameListAdapter( Context context ) { - super( context, GameUtils.gamesList(context).length ); + super( context, DBUtils.gamesList(context).length ); m_context = context; m_factory = LayoutInflater.from( context ); @@ -56,12 +56,12 @@ public class GameListAdapter extends XWListAdapter { } public int getCount() { - return GameUtils.gamesList(m_context).length; + return DBUtils.gamesList(m_context).length; } public Object getItem( int position ) { - final String path = GameUtils.gamesList(m_context)[position]; + final String path = DBUtils.gamesList(m_context)[position]; View layout = m_viewsCache.get( path ); if ( null == layout ) { diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java index f54b38040..566510910 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java @@ -40,23 +40,7 @@ public class GameUtils { public static byte[] savedGame( Context context, String path ) { - byte[] stream = null; - try { - synchronized( s_syncObj ) { - FileInputStream in = context.openFileInput( path ); - int len = in.available(); - stream = new byte[len]; - in.read( stream, 0, len ); - in.close(); - } - } catch ( java.io.FileNotFoundException fnf ) { - Utils.logf( fnf.toString() ); - stream = null; - } catch ( java.io.IOException io ) { - Utils.logf( io.toString() ); - stream = null; - } - return stream; + return DBUtils.loadGame( context, path ); } // savedGame /** @@ -125,17 +109,6 @@ public class GameUtils { return summary; } - public static String[] gamesList( Context context ) - { - ArrayList al = new ArrayList(); - for ( String file : context.fileList() ) { - if ( isGame( file ) ){ - al.add( file ); - } - } - return al.toArray( new String[al.size()] ); - } - public static String dupeGame( Context context, String pathIn ) { String newName = newName( context ); @@ -148,8 +121,7 @@ public class GameUtils { { // does this need to be synchronized? tellRelayDied( context, path, informNow ); - context.deleteFile( path ); - DBUtils.saveSummary( context, path, null ); + DBUtils.deleteGame( context, path ); } public static void loadMakeGame( Context context, int gamePtr, @@ -185,16 +157,17 @@ public class GameUtils { public static void saveGame( Context context, byte[] bytes, String path ) { - try { - synchronized( s_syncObj ) { - FileOutputStream out = - context.openFileOutput( path, Context.MODE_PRIVATE ); - out.write( bytes ); - out.close(); - } - } catch ( java.io.IOException ex ) { - Utils.logf( "got IOException: " + ex.toString() ); - } + DBUtils.saveGame( context, path, bytes ); + // try { + // synchronized( s_syncObj ) { + // FileOutputStream out = + // context.openFileOutput( path, Context.MODE_PRIVATE ); + // out.write( bytes ); + // out.close(); + // } + // } catch ( java.io.IOException ex ) { + // Utils.logf( "got IOException: " + ex.toString() ); + // } } public static String saveGame( Context context, byte[] bytes ) @@ -228,7 +201,7 @@ public class GameUtils { public static boolean gameDictHere( Context context, int indx, String[] name, int[] lang ) { - String path = GameUtils.gamesList( context )[indx]; + String path = DBUtils.gamesList( context )[indx]; return gameDictHere( context, path, name, lang ); } @@ -237,7 +210,7 @@ public class GameUtils { String name = null; Integer num = 1; int ii; - String[] files = context.fileList(); + String[] files = DBUtils.gamesList( context ); String fmt = context.getString( R.string.gamef ); while ( name == null ) { diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java index f70abbe18..2f736bb4a 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java @@ -153,6 +153,8 @@ public class GamesList extends XWListActivity } }); + GameConverter.convert( this ); + m_adapter = new GameListAdapter( this ); setListAdapter( m_adapter ); @@ -281,12 +283,12 @@ public class GamesList extends XWListActivity switch (item.getItemId()) { case R.id.gamel_menu_delete_all: - if ( GameUtils.gamesList( this ).length > 0 ) { + if ( DBUtils.gamesList( this ).length > 0 ) { DialogInterface.OnClickListener lstnr = new DialogInterface.OnClickListener() { public void onClick( DialogInterface dlg, int item ) { String[] games = - GameUtils.gamesList( GamesList.this ); + DBUtils.gamesList( GamesList.this ); for ( int ii = games.length - 1; ii >= 0; --ii ) { GameUtils.deleteGame( GamesList.this, games[ii], ii == 0 ); @@ -338,7 +340,7 @@ public class GamesList extends XWListActivity protected void onListItemClick( ListView l, View v, int position, long id ) { super.onListItemClick( l, v, position, id ); - String path = GameUtils.gamesList( this )[position]; + String path = DBUtils.gamesList( this )[position]; // We need a way to let the user get back to the basic-config // dialog in case it was dismissed. That way it to check for @@ -373,7 +375,7 @@ public class GamesList extends XWListActivity boolean handled = true; DialogInterface.OnClickListener lstnr; - final String path = GameUtils.gamesList( this )[position]; + final String path = DBUtils.gamesList( this )[position]; if ( R.id.list_item_delete == menuID ) { lstnr = new DialogInterface.OnClickListener() {