diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardCanvas.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardCanvas.java index faf80aee5..0c06a4b41 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardCanvas.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardCanvas.java @@ -82,7 +82,7 @@ public class BoardCanvas extends Canvas implements DrawCtx { private int m_trayOwner = -1; private int m_pendingScore; private int m_dictPtr = 0; - private String[] m_dictChars; + protected String[] m_dictChars; private boolean m_hasSmallScreen; private int m_backgroundUsed = 0x00000000; @@ -118,7 +118,7 @@ public class BoardCanvas extends Canvas implements DrawCtx { int descentFor( int ht ) { return (int)(ht * m_descentProportion); } int widthFor( int width ) { return (int)(width / m_widthProportion); } } - private FontDims m_fontDims; + protected FontDims m_fontDims; public BoardCanvas( Activity activity, Bitmap bitmap, JNIThread jniThread, BoardDims dims ) 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 3b753b288..a8ecd6462 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java @@ -135,7 +135,7 @@ public class DBUtils { DBHelper.DICTLANG, DBHelper.GAMEID, DBHelper.SCORES, DBHelper.HASMSGS, DBHelper.LASTPLAY_TIME, DBHelper.REMOTEDEVS, - DBHelper.LASTMOVE, DBHelper.THUMBNAIL + DBHelper.LASTMOVE }; String selection = String.format( ROW_ID_FMT, lock.getRowid() ); @@ -184,18 +184,6 @@ public class DBUtils { summary.lastMoveTime = cursor.getInt(cursor.getColumnIndex(DBHelper.LASTMOVE)); - if ( BuildConstants.THUMBNAIL_SUPPORTED ) { - byte[] data = - cursor.getBlob( cursor. - getColumnIndex(DBHelper.THUMBNAIL)); - if ( null != data ) { - Bitmap thumb = - BitmapFactory.decodeByteArray( data, 0, - data.length ); - summary.setThumbnail( thumb ); - } - } - String scoresStr = cursor.getString( cursor.getColumnIndex(DBHelper.SCORES)); int[] scores = new int[summary.nPlayers]; @@ -322,8 +310,6 @@ public class DBUtils { } values.put( DBHelper.SERVERROLE, summary.serverRole.ordinal() ); - - addThumb( summary.getThumbnail(), values ); } initDB( context ); @@ -447,7 +433,15 @@ public class DBUtils { long rowid = lock.getRowid(); String selection = String.format( ROW_ID_FMT, rowid ); ContentValues values = new ContentValues(); - addThumb( thumb, values ); + + if ( null == thumb ) { + values.putNull( DBHelper.THUMBNAIL ); + } else { + ByteArrayOutputStream bas = new ByteArrayOutputStream(); + thumb.compress( CompressFormat.PNG, 0, bas ); + values.put( DBHelper.THUMBNAIL, bas.toByteArray() ); + } + initDB( context ); synchronized( s_dbHelper ) { SQLiteDatabase db = s_dbHelper.getWritableDatabase(); @@ -957,15 +951,32 @@ public class DBUtils { s_groupsCache = null; } - private static void addThumb( Bitmap thumb, ContentValues values ) + public static Bitmap getThumb( Context context, long rowid ) { - if ( null == thumb ) { - values.putNull( DBHelper.THUMBNAIL ); - } else { - ByteArrayOutputStream bas = new ByteArrayOutputStream(); - thumb.compress( CompressFormat.PNG, 0, bas ); - values.put( DBHelper.THUMBNAIL, bas.toByteArray() ); + Bitmap thumb = null; + if ( BuildConstants.THUMBNAIL_SUPPORTED ) { + byte[] data = null; + String[] columns = { DBHelper.THUMBNAIL }; + String selection = String.format( ROW_ID_FMT, rowid ); + + initDB( context ); + synchronized( s_dbHelper ) { + SQLiteDatabase db = s_dbHelper.getReadableDatabase(); + Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns, + selection, null, null, null, null ); + if ( 1 == cursor.getCount() && cursor.moveToFirst() ) { + data = cursor.getBlob( cursor. + getColumnIndex(DBHelper.THUMBNAIL)); + } + cursor.close(); + db.close(); + } + + if ( null != data ) { + thumb = BitmapFactory.decodeByteArray( data, 0, data.length ); + } } + return thumb; } // Return map of string (group name) to info about all games in diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListItem.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListItem.java index 6b621e357..4c021de82 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListItem.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListItem.java @@ -30,6 +30,7 @@ import android.os.AsyncTask; import android.os.Handler; import android.util.AttributeSet; import android.view.View; +import java.util.concurrent.LinkedBlockingQueue; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; @@ -310,7 +311,6 @@ public class GameListItem extends LinearLayout if ( BuildConstants.THUMBNAIL_SUPPORTED ) { m_thumb = (ImageView)findViewById( R.id.thumbnail ); - m_thumb.setImageBitmap( summary.getThumbnail() ); } tview = (TextView)findViewById( R.id.role ); @@ -340,11 +340,9 @@ public class GameListItem extends LinearLayout private void makeThumbnailIf( boolean expanded ) { - if ( expanded && null != m_activity && null != m_summary - && null == m_summary.getThumbnail() + if ( expanded && null != m_activity && XWPrefs.getThumbEnabled( m_context ) ) { - m_summary.setThumbnail( GameUtils.loadMakeBitmap( m_activity, - m_rowid ) ); + enqueueGetThumbnail( this, m_rowid ); } } @@ -412,4 +410,67 @@ public class GameListItem extends LinearLayout toggleSelected(); } + private static class ThumbQueueElem { + public ThumbQueueElem( GameListItem item, long rowid ) { + m_item = item; + m_rowid = rowid; + } + long m_rowid; + GameListItem m_item; + } + private static LinkedBlockingQueue s_queue + = new LinkedBlockingQueue(); + private static Thread s_thumbThread; + + private static void enqueueGetThumbnail( GameListItem item, long rowid ) + { + if ( BuildConstants.THUMBNAIL_SUPPORTED ) { + s_queue.add( new ThumbQueueElem( item, rowid ) ); + + synchronized( GameListItem.class ) { + if ( null == s_thumbThread ) { + s_thumbThread = makeThumbThread(); + s_thumbThread.start(); + } + } + } + } + + private static Thread makeThumbThread() + { + return new Thread( new Runnable() { + public void run() + { + for ( ; ; ) { + ThumbQueueElem elem; + try { + elem = s_queue.take(); + } catch ( InterruptedException ie ) { + DbgUtils.logf( "interrupted; killing " + + "s_thumbThread" ); + break; + } + Activity activity = elem.m_item.m_activity; + long rowid = elem.m_rowid; + Bitmap thumb = DBUtils.getThumb( activity, rowid ); + if ( null == thumb ) { + // loadMakeBitmap puts in DB + thumb = GameUtils.loadMakeBitmap( activity, rowid ); + } + + final GameListItem item = elem.m_item; + final Bitmap ft = thumb; + activity.runOnUiThread( new Runnable() { + public void run() { + ImageView iview = item.m_thumb; + if ( null != iview ) { + iview.setImageBitmap( ft ); + } + } + }); + } + } + }); + } + } diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/ThumbCanvas.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/ThumbCanvas.java index 87218cd74..dc778ca66 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/ThumbCanvas.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/ThumbCanvas.java @@ -24,6 +24,8 @@ import android.app.Activity; import android.graphics.Bitmap; import android.graphics.Rect; +import org.eehouse.android.xw4.jni.XwJNI; + public class ThumbCanvas extends BoardCanvas { public ThumbCanvas( Activity activity, Bitmap bitmap ) @@ -47,4 +49,17 @@ public class ThumbCanvas extends BoardCanvas { return false; } + // Unlike superclass, where the game was loaded on the main thread + // but dictChanged() is called on the JNI thread, this instance + // will have been created on the same background thread that's + // calling us. So don't switch threads for the dict_getChars() + // call + @Override + public void dictChanged( final int dictPtr ) + { + if ( 0 != dictPtr ) { + m_fontDims = null; + m_dictChars = XwJNI.dict_getChars( dictPtr ); + } + } } diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/GameSummary.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/GameSummary.java index d179ef1ad..e7779652f 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/GameSummary.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/GameSummary.java @@ -21,7 +21,6 @@ package org.eehouse.android.xw4.jni; import android.content.Context; -import android.graphics.Bitmap; import android.text.TextUtils; import junit.framework.Assert; @@ -69,7 +68,6 @@ public class GameSummary { private CurGameInfo m_gi; private Context m_context; private String[] m_remotePhones; - private Bitmap m_thumb; private GameSummary() {} @@ -89,16 +87,6 @@ public class GameSummary { m_gi = gi; } - public void setThumbnail( Bitmap thumb ) - { - m_thumb = thumb; - } - - public Bitmap getThumbnail() - { - return m_thumb; - } - public boolean inNetworkGame() { return null != relayID;