mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-03 23:04:08 +01:00
Merge branch 'android_branch' into send_in_background
This commit is contained in:
commit
eb0e41e978
17 changed files with 735 additions and 482 deletions
|
@ -513,7 +513,6 @@ makeDict( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil, jstring jname,
|
||||||
|
|
||||||
/* copy the name */
|
/* copy the name */
|
||||||
anddict->super.name = getStringCopy( MPPARM(mpool) env, jname );
|
anddict->super.name = getStringCopy( MPPARM(mpool) env, jname );
|
||||||
XP_LOGF( "%s: setting dict name: %s", __func__, anddict->super.name );
|
|
||||||
anddict->super.langName = getStringCopy( MPPARM(mpool) env, jlangname );
|
anddict->super.langName = getStringCopy( MPPARM(mpool) env, jlangname );
|
||||||
|
|
||||||
return (DictionaryCtxt*)anddict;
|
return (DictionaryCtxt*)anddict;
|
||||||
|
|
|
@ -125,7 +125,9 @@
|
||||||
<item>@string/connect_daily</item>
|
<item>@string/connect_daily</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<!-- Keep in sync with DictUtils.DictLoc enum -->
|
||||||
<string-array name="loc_names">
|
<string-array name="loc_names">
|
||||||
|
<item></item>
|
||||||
<item>@string/loc_builtin</item>
|
<item>@string/loc_builtin</item>
|
||||||
<item>@string/loc_internal</item>
|
<item>@string/loc_internal</item>
|
||||||
<item>@string/loc_external</item>
|
<item>@string/loc_external</item>
|
||||||
|
|
|
@ -216,8 +216,8 @@
|
||||||
wordlist installed. One or more games will be unopenable
|
wordlist installed. One or more games will be unopenable
|
||||||
without it.</string>
|
without it.</string>
|
||||||
<string name="confirm_deletemore_dictf">\u0020One game (at least)
|
<string name="confirm_deletemore_dictf">\u0020One game (at least)
|
||||||
is using it (but there is another %s wordlist installed that
|
is using it, but there is another %s wordlist installed that can
|
||||||
can replace it.)</string>
|
replace it.</string>
|
||||||
|
|
||||||
<string name="hints_allowed">Allow hints</string>
|
<string name="hints_allowed">Allow hints</string>
|
||||||
<string name="hints_allowed_sum">Enable the hint feature</string>
|
<string name="hints_allowed_sum">Enable the hint feature</string>
|
||||||
|
|
|
@ -1170,7 +1170,7 @@ public class BoardActivity extends XWActivity
|
||||||
{
|
{
|
||||||
if ( 0 == m_jniGamePtr ) {
|
if ( 0 == m_jniGamePtr ) {
|
||||||
String[] dictNames = GameUtils.dictNames( this, m_rowid );
|
String[] dictNames = GameUtils.dictNames( this, m_rowid );
|
||||||
GameUtils.DictPairs pairs = GameUtils.openDicts( this, dictNames );
|
DictUtils.DictPairs pairs = DictUtils.openDicts( this, dictNames );
|
||||||
|
|
||||||
if ( pairs.anyMissing( dictNames ) ) {
|
if ( pairs.anyMissing( dictNames ) ) {
|
||||||
showDictGoneFinish();
|
showDictGoneFinish();
|
||||||
|
|
|
@ -29,7 +29,7 @@ public class DBHelper extends SQLiteOpenHelper {
|
||||||
public static final String TABLE_NAME_SUM = "summaries";
|
public static final String TABLE_NAME_SUM = "summaries";
|
||||||
public static final String TABLE_NAME_OBITS = "obits";
|
public static final String TABLE_NAME_OBITS = "obits";
|
||||||
private static final String DB_NAME = "xwdb";
|
private static final String DB_NAME = "xwdb";
|
||||||
private static final int DB_VERSION = 9;
|
private static final int DB_VERSION = 10;
|
||||||
|
|
||||||
public static final String GAME_NAME = "GAME_NAME";
|
public static final String GAME_NAME = "GAME_NAME";
|
||||||
public static final String NUM_MOVES = "NUM_MOVES";
|
public static final String NUM_MOVES = "NUM_MOVES";
|
||||||
|
@ -48,6 +48,7 @@ public class DBHelper extends SQLiteOpenHelper {
|
||||||
// format
|
// format
|
||||||
public static final String GAMEID = "GAMEID";
|
public static final String GAMEID = "GAMEID";
|
||||||
public static final String DICTLANG = "DICTLANG";
|
public static final String DICTLANG = "DICTLANG";
|
||||||
|
public static final String DICTLIST = "DICTLIST";
|
||||||
public static final String HASMSGS = "HASMSGS";
|
public static final String HASMSGS = "HASMSGS";
|
||||||
public static final String CONTRACTED = "CONTRACTED";
|
public static final String CONTRACTED = "CONTRACTED";
|
||||||
public static final String SNAPSHOT = "SNAPSHOT";
|
public static final String SNAPSHOT = "SNAPSHOT";
|
||||||
|
@ -87,6 +88,7 @@ public class DBHelper extends SQLiteOpenHelper {
|
||||||
+ RELAYID + " TEXT,"
|
+ RELAYID + " TEXT,"
|
||||||
+ SEED + " INTEGER,"
|
+ SEED + " INTEGER,"
|
||||||
+ DICTLANG + " INTEGER,"
|
+ DICTLANG + " INTEGER,"
|
||||||
|
+ DICTLIST + " TEXT,"
|
||||||
|
|
||||||
+ SMSPHONE + " TEXT,"
|
+ SMSPHONE + " TEXT,"
|
||||||
+ SCORES + " TEXT,"
|
+ SCORES + " TEXT,"
|
||||||
|
@ -142,6 +144,9 @@ public class DBHelper extends SQLiteOpenHelper {
|
||||||
db.execSQL( "ALTER TABLE " + TABLE_NAME_SUM +
|
db.execSQL( "ALTER TABLE " + TABLE_NAME_SUM +
|
||||||
" ADD COLUMN " + CONTRACTED + " INTEGER;" );
|
" ADD COLUMN " + CONTRACTED + " INTEGER;" );
|
||||||
case 9:
|
case 9:
|
||||||
|
db.execSQL( "ALTER TABLE " + TABLE_NAME_SUM +
|
||||||
|
" ADD COLUMN " + DICTLIST + " TEXT;" );
|
||||||
|
case 10:
|
||||||
// nothing yet
|
// nothing yet
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -38,6 +38,8 @@ import org.eehouse.android.xw4.jni.*;
|
||||||
|
|
||||||
public class DBUtils {
|
public class DBUtils {
|
||||||
|
|
||||||
|
private static final String DICTS_SEP = ",";
|
||||||
|
|
||||||
private static final String ROW_ID = "rowid";
|
private static final String ROW_ID = "rowid";
|
||||||
private static final String ROW_ID_FMT = "rowid=%d";
|
private static final String ROW_ID_FMT = "rowid=%d";
|
||||||
|
|
||||||
|
@ -226,6 +228,7 @@ public class DBUtils {
|
||||||
summary.summarizePlayers() );
|
summary.summarizePlayers() );
|
||||||
values.put( DBHelper.DICTLANG, summary.dictLang );
|
values.put( DBHelper.DICTLANG, summary.dictLang );
|
||||||
values.put( DBHelper.GAME_OVER, summary.gameOver );
|
values.put( DBHelper.GAME_OVER, summary.gameOver );
|
||||||
|
values.put( DBHelper.DICTLIST, summary.dictNames(DICTS_SEP) );
|
||||||
|
|
||||||
if ( null != summary.scores ) {
|
if ( null != summary.scores ) {
|
||||||
StringBuffer sb = new StringBuffer();
|
StringBuffer sb = new StringBuffer();
|
||||||
|
@ -253,7 +256,7 @@ public class DBUtils {
|
||||||
}
|
}
|
||||||
} // saveSummary
|
} // saveSummary
|
||||||
|
|
||||||
public static int countGamesUsing( Context context, int lang )
|
public static int countGamesUsingLang( Context context, int lang )
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
initDB( context );
|
initDB( context );
|
||||||
|
@ -273,6 +276,28 @@ public class DBUtils {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int countGamesUsingDict( Context context, String dict )
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
initDB( context );
|
||||||
|
synchronized( s_dbHelper ) {
|
||||||
|
SQLiteDatabase db = s_dbHelper.getReadableDatabase();
|
||||||
|
String pattern = String.format( "%%%s%s%s%%",
|
||||||
|
DICTS_SEP, dict, DICTS_SEP );
|
||||||
|
String selection = String.format( "%s LIKE '%s'",
|
||||||
|
DBHelper.DICTLIST, pattern );
|
||||||
|
// null for columns will return whole rows: bad. But
|
||||||
|
// might as well make it an int for speed
|
||||||
|
String[] columns = { DBHelper.DICTLANG };
|
||||||
|
Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns,
|
||||||
|
selection, null, null, null, null );
|
||||||
|
result = cursor.getCount();
|
||||||
|
cursor.close();
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private static void setInt( long rowid, String column, int value )
|
private static void setInt( long rowid, String column, int value )
|
||||||
{
|
{
|
||||||
synchronized( s_dbHelper ) {
|
synchronized( s_dbHelper ) {
|
||||||
|
|
|
@ -36,11 +36,12 @@ import junit.framework.Assert;
|
||||||
|
|
||||||
public class DictImportActivity extends XWActivity {
|
public class DictImportActivity extends XWActivity {
|
||||||
|
|
||||||
private static boolean s_useSD = false;
|
private static DictUtils.DictLoc s_saveWhere = DictUtils.DictLoc.INTERNAL;
|
||||||
|
|
||||||
public static void setUseSD( boolean useSD )
|
public static void setUseSD( boolean useSD )
|
||||||
{
|
{
|
||||||
s_useSD = useSD;
|
s_saveWhere = useSD ?
|
||||||
|
DictUtils.DictLoc.EXTERNAL : DictUtils.DictLoc.INTERNAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DownloadFilesTask extends AsyncTask<Uri, Integer, Long> {
|
private class DownloadFilesTask extends AsyncTask<Uri, Integer, Long> {
|
||||||
|
@ -80,7 +81,8 @@ public class DictImportActivity extends XWActivity {
|
||||||
{
|
{
|
||||||
Utils.logf( "onPostExecute passed %d", result );
|
Utils.logf( "onPostExecute passed %d", result );
|
||||||
if ( null != m_saved ) {
|
if ( null != m_saved ) {
|
||||||
DictLangCache.inval( DictImportActivity.this, m_saved, true );
|
DictLangCache.inval( DictImportActivity.this, m_saved,
|
||||||
|
s_saveWhere, true );
|
||||||
}
|
}
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
@ -121,7 +123,7 @@ public class DictImportActivity extends XWActivity {
|
||||||
private String saveDict( InputStream inputStream, String path )
|
private String saveDict( InputStream inputStream, String path )
|
||||||
{
|
{
|
||||||
String name = basename( path );
|
String name = basename( path );
|
||||||
if ( GameUtils.saveDict( this, inputStream, name, s_useSD ) ) {
|
if ( DictUtils.saveDict( this, inputStream, name, s_saveWhere ) ) {
|
||||||
return name;
|
return name;
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -27,17 +27,20 @@ import android.widget.ArrayAdapter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import junit.framework.Assert;
|
||||||
|
|
||||||
|
import org.eehouse.android.xw4.DictUtils.DictAndLoc;
|
||||||
import org.eehouse.android.xw4.jni.JNIUtilsImpl;
|
import org.eehouse.android.xw4.jni.JNIUtilsImpl;
|
||||||
import org.eehouse.android.xw4.jni.XwJNI;
|
import org.eehouse.android.xw4.jni.XwJNI;
|
||||||
import org.eehouse.android.xw4.jni.DictInfo;
|
import org.eehouse.android.xw4.jni.DictInfo;
|
||||||
import org.eehouse.android.xw4.jni.CommonPrefs;
|
import org.eehouse.android.xw4.jni.CommonPrefs;
|
||||||
|
|
||||||
public class DictLangCache {
|
public class DictLangCache {
|
||||||
private static final HashMap<String,DictInfo> s_nameToLang =
|
private static final HashMap<DictAndLoc,DictInfo> s_nameToLang =
|
||||||
new HashMap<String,DictInfo>();
|
new HashMap<DictAndLoc,DictInfo>();
|
||||||
private static String[] s_langNames;
|
private static String[] s_langNames;
|
||||||
|
|
||||||
private static int m_adaptedLang = -1;
|
private static int m_adaptedLang = -1;
|
||||||
|
@ -59,17 +62,18 @@ public class DictLangCache {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static String annotatedDictName( Context context, String name )
|
public static String annotatedDictName( Context context, DictAndLoc dal )
|
||||||
{
|
{
|
||||||
DictInfo info = getInfo( context, name );
|
DictInfo info = getInfo( context, dal );
|
||||||
int wordCount = info.wordCount;
|
int wordCount = info.wordCount;
|
||||||
|
|
||||||
String langName = getLangName( context, name );
|
String langName = getLangName( context, dal.name );
|
||||||
String result;
|
String result;
|
||||||
if ( 0 == wordCount ) {
|
if ( 0 == wordCount ) {
|
||||||
result = String.format( "%s (%s)", name, langName );
|
result = String.format( "%s (%s)", dal.name, langName );
|
||||||
} else {
|
} else {
|
||||||
result = String.format( "%s (%s/%d)", name, langName, wordCount );
|
result = String.format( "%s (%s/%d)", dal.name, langName,
|
||||||
|
wordCount );
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -95,9 +99,9 @@ public class DictLangCache {
|
||||||
public static int getLangCount( Context context, int code )
|
public static int getLangCount( Context context, int code )
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
String[] dicts = GameUtils.dictList( context );
|
DictAndLoc[] dals = DictUtils.dictList( context );
|
||||||
for ( String dict : dicts ) {
|
for ( DictAndLoc dal : dals ) {
|
||||||
if ( code == getDictLangCode( context, dict ) ) {
|
if ( code == getDictLangCode( context, dal ) ) {
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,9 +111,9 @@ public class DictLangCache {
|
||||||
private static DictInfo[] getInfosHaveLang( Context context, int code )
|
private static DictInfo[] getInfosHaveLang( Context context, int code )
|
||||||
{
|
{
|
||||||
ArrayList<DictInfo> al = new ArrayList<DictInfo>();
|
ArrayList<DictInfo> al = new ArrayList<DictInfo>();
|
||||||
String[] dicts = GameUtils.dictList( context );
|
DictAndLoc[] dals = DictUtils.dictList( context );
|
||||||
for ( String dict : dicts ) {
|
for ( DictAndLoc dal : dals ) {
|
||||||
DictInfo info = getInfo( context, dict );
|
DictInfo info = getInfo( context, dal );
|
||||||
if ( code == info.langCode ) {
|
if ( code == info.langCode ) {
|
||||||
al.add( info );
|
al.add( info );
|
||||||
}
|
}
|
||||||
|
@ -149,6 +153,20 @@ public class DictLangCache {
|
||||||
return getHaveLang( context, code, null, false );
|
return getHaveLang( context, code, null, false );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static DictAndLoc[] getDALsHaveLang( Context context, int code )
|
||||||
|
{
|
||||||
|
ArrayList<DictAndLoc> al = new ArrayList<DictAndLoc>();
|
||||||
|
DictAndLoc[] dals = DictUtils.dictList( context );
|
||||||
|
for ( DictAndLoc dal : dals ) {
|
||||||
|
DictInfo info = getInfo( context, dal );
|
||||||
|
if ( code == info.langCode ) {
|
||||||
|
al.add( dal );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DictAndLoc[] result = al.toArray( new DictAndLoc[al.size()] );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private static Comparator<DictInfo> s_ByCount =
|
private static Comparator<DictInfo> s_ByCount =
|
||||||
new Comparator<DictInfo>() {
|
new Comparator<DictInfo>() {
|
||||||
public int compare( DictInfo di1, DictInfo di2 )
|
public int compare( DictInfo di1, DictInfo di2 )
|
||||||
|
@ -173,6 +191,11 @@ public class DictLangCache {
|
||||||
return nameWithCount.substring( 0, indx );
|
return nameWithCount.substring( 0, indx );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int getDictLangCode( Context context, DictAndLoc dal )
|
||||||
|
{
|
||||||
|
return getInfo( context, dal ).langCode;
|
||||||
|
}
|
||||||
|
|
||||||
public static int getDictLangCode( Context context, String dict )
|
public static int getDictLangCode( Context context, String dict )
|
||||||
{
|
{
|
||||||
return getInfo( context, dict ).langCode;
|
return getInfo( context, dict ).langCode;
|
||||||
|
@ -198,12 +221,12 @@ public class DictLangCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void inval( final Context context, String name,
|
public static void inval( final Context context, String name,
|
||||||
boolean added )
|
DictUtils.DictLoc loc, boolean added )
|
||||||
{
|
{
|
||||||
name = GameUtils.removeDictExtn( name );
|
DictAndLoc dal = new DictAndLoc( name, loc );
|
||||||
s_nameToLang.remove( name );
|
s_nameToLang.remove( dal );
|
||||||
if ( added ) {
|
if ( added ) {
|
||||||
getInfo( context, name );
|
getInfo( context, dal );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( null != s_handler ) {
|
if ( null != s_handler ) {
|
||||||
|
@ -226,14 +249,14 @@ public class DictLangCache {
|
||||||
|
|
||||||
public static String[] listLangs( Context context )
|
public static String[] listLangs( Context context )
|
||||||
{
|
{
|
||||||
return listLangs( context, GameUtils.dictList( context ) );
|
return listLangs( context, DictUtils.dictList( context ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String[] listLangs( Context context, final String[] names )
|
public static String[] listLangs( Context context, DictAndLoc[] dals )
|
||||||
{
|
{
|
||||||
HashSet<String> langs = new HashSet<String>();
|
HashSet<String> langs = new HashSet<String>();
|
||||||
for ( String name:names ) {
|
for ( DictAndLoc dal : dals ) {
|
||||||
langs.add( getLangName( context, name ) );
|
langs.add( getLangName( context, dal.name ) );
|
||||||
}
|
}
|
||||||
String[] result = new String[langs.size()];
|
String[] result = new String[langs.size()];
|
||||||
return langs.toArray( result );
|
return langs.toArray( result );
|
||||||
|
@ -309,18 +332,52 @@ public class DictLangCache {
|
||||||
return s_langNames;
|
return s_langNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int getDictCount( Context context, String name )
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
for ( DictAndLoc dal : DictUtils.dictList( context ) ) {
|
||||||
|
if ( name.equals( dal.name ) ) {
|
||||||
|
++result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Assert.assertTrue( result > 0 );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private static DictInfo getInfo( Context context, String name )
|
private static DictInfo getInfo( Context context, String name )
|
||||||
|
{
|
||||||
|
DictInfo result = null;
|
||||||
|
Set<DictAndLoc> keys = s_nameToLang.keySet();
|
||||||
|
for ( DictAndLoc key : keys ) {
|
||||||
|
if ( key.name.equals(name) ) {
|
||||||
|
result = s_nameToLang.get( key );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( null == result ) {
|
||||||
|
DictUtils.DictLoc loc = DictUtils.getDictLoc( context, name );
|
||||||
|
result = getInfo( context, new DictAndLoc( name, loc ) );
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DictInfo getInfo( Context context, DictAndLoc dal )
|
||||||
{
|
{
|
||||||
DictInfo info;
|
DictInfo info;
|
||||||
if ( s_nameToLang.containsKey( name ) ) {
|
if ( s_nameToLang.containsKey( dal ) ) {
|
||||||
info = s_nameToLang.get( name );
|
info = s_nameToLang.get( dal );
|
||||||
} else {
|
} else {
|
||||||
byte[] dict = GameUtils.openDict( context, name );
|
String[] names = { dal.name };
|
||||||
String path = GameUtils.getDictPath( context, name );
|
DictUtils.DictPairs pairs = DictUtils.openDicts( context, names );
|
||||||
|
|
||||||
info = new DictInfo();
|
info = new DictInfo();
|
||||||
XwJNI.dict_getInfo( dict, path, JNIUtilsImpl.get(), info );
|
|
||||||
info.name = name;
|
XwJNI.dict_getInfo( pairs.m_bytes[0], pairs.m_paths[0],
|
||||||
s_nameToLang.put( name, info );
|
JNIUtilsImpl.get(), info );
|
||||||
|
|
||||||
|
info.name = dal.name;
|
||||||
|
s_nameToLang.put( dal, info );
|
||||||
}
|
}
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,13 +32,15 @@ public class DictListPreference extends XWListPreference {
|
||||||
{
|
{
|
||||||
super( context, attrs );
|
super( context, attrs );
|
||||||
|
|
||||||
String[] dicts = GameUtils.dictList( context );
|
DictUtils.DictAndLoc[] dals = DictUtils.dictList( context );
|
||||||
String[] dictEntries = new String[dicts.length];
|
String[] dictEntries = new String[dals.length];
|
||||||
for ( int ii = 0; ii < dicts.length; ++ii ) {
|
String[] values = new String[dals.length];
|
||||||
|
for ( int ii = 0; ii < dals.length; ++ii ) {
|
||||||
|
values[ii] = dals[ii].name;
|
||||||
dictEntries[ii] =
|
dictEntries[ii] =
|
||||||
DictLangCache.annotatedDictName( context, dicts[ii] );
|
DictLangCache.annotatedDictName( context, dals[ii] );
|
||||||
}
|
}
|
||||||
setEntries( dictEntries );
|
setEntries( dictEntries );
|
||||||
setEntryValues( dicts );
|
setEntryValues( values );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,497 @@
|
||||||
|
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
|
||||||
|
/*
|
||||||
|
* Copyright 2009-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.app.Activity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Environment;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import android.content.res.AssetManager;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Random;
|
||||||
|
import android.text.Html;
|
||||||
|
|
||||||
|
import junit.framework.Assert;
|
||||||
|
|
||||||
|
import org.eehouse.android.xw4.jni.*;
|
||||||
|
import org.eehouse.android.xw4.jni.CurGameInfo.DeviceRole;
|
||||||
|
|
||||||
|
public class DictUtils {
|
||||||
|
|
||||||
|
// keep in sync with loc_names string-array
|
||||||
|
public enum DictLoc { UNKNOWN, BUILT_IN, INTERNAL, EXTERNAL, DOWNLOAD };
|
||||||
|
public static final String INVITED = "invited";
|
||||||
|
|
||||||
|
private static DictAndLoc[] s_dictListCache = null;
|
||||||
|
|
||||||
|
public static class DictPairs {
|
||||||
|
public byte[][] m_bytes;
|
||||||
|
public String[] m_paths;
|
||||||
|
public DictPairs( byte[][] bytes, String[] paths ) {
|
||||||
|
m_bytes = bytes; m_paths = paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean anyMissing( final String[] names )
|
||||||
|
{
|
||||||
|
boolean missing = false;
|
||||||
|
for ( int ii = 0; ii < m_paths.length; ++ii ) {
|
||||||
|
if ( names[ii] != null ) {
|
||||||
|
// It's ok for there to be no dict IFF there's no
|
||||||
|
// name. That's a player using the default dict.
|
||||||
|
if ( null == m_paths[ii] && null == m_bytes[ii] ) {
|
||||||
|
missing = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return missing;
|
||||||
|
}
|
||||||
|
} // DictPairs
|
||||||
|
|
||||||
|
public static class DictAndLoc {
|
||||||
|
public DictAndLoc( String pname, DictLoc ploc ) {
|
||||||
|
name = removeDictExtn(pname); loc = ploc;
|
||||||
|
}
|
||||||
|
public String name;
|
||||||
|
public DictLoc loc;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals( Object obj )
|
||||||
|
{
|
||||||
|
boolean result = false;
|
||||||
|
if ( obj instanceof DictAndLoc ) {
|
||||||
|
DictAndLoc other = (DictAndLoc)obj;
|
||||||
|
|
||||||
|
result = name.equals( other.name )
|
||||||
|
&& loc.equals( other.loc );
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DictAndLoc[] dictList( Context context )
|
||||||
|
{
|
||||||
|
if ( null == s_dictListCache ) {
|
||||||
|
ArrayList<DictAndLoc> al = new ArrayList<DictAndLoc>();
|
||||||
|
|
||||||
|
for ( String file : getAssets( context ) ) {
|
||||||
|
if ( isDict( file ) ) {
|
||||||
|
al.add( new DictAndLoc( removeDictExtn( file ),
|
||||||
|
DictLoc.BUILT_IN ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( String file : context.fileList() ) {
|
||||||
|
if ( isDict( file ) ) {
|
||||||
|
al.add( new DictAndLoc( removeDictExtn( file ),
|
||||||
|
DictLoc.INTERNAL ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
File sdDir = getSDDir( context );
|
||||||
|
if ( null != sdDir ) {
|
||||||
|
for ( String file : sdDir.list() ) {
|
||||||
|
if ( isDict( file ) ) {
|
||||||
|
al.add( new DictAndLoc( removeDictExtn( file ),
|
||||||
|
DictLoc.EXTERNAL ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s_dictListCache =
|
||||||
|
al.toArray( new DictUtils.DictAndLoc[al.size()] );
|
||||||
|
}
|
||||||
|
return s_dictListCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DictLoc getDictLoc( Context context, String name )
|
||||||
|
{
|
||||||
|
DictLoc loc = null;
|
||||||
|
name = addDictExtn( name );
|
||||||
|
|
||||||
|
for ( String file : getAssets( context ) ) {
|
||||||
|
if ( file.equals( name ) ) {
|
||||||
|
loc = DictLoc.BUILT_IN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( null == loc ) {
|
||||||
|
try {
|
||||||
|
FileInputStream fis = context.openFileInput( name );
|
||||||
|
fis.close();
|
||||||
|
loc = DictLoc.INTERNAL;
|
||||||
|
} catch ( java.io.FileNotFoundException fnf ) {
|
||||||
|
} catch ( java.io.IOException ioe ) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( null == loc ) {
|
||||||
|
File file = getSDPathFor( context, name );
|
||||||
|
if ( null != file && file.exists() ) {
|
||||||
|
loc = DictLoc.EXTERNAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return loc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean dictExists( Context context, String name )
|
||||||
|
{
|
||||||
|
return null != getDictLoc( context, name );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean dictIsBuiltin( Context context, String name )
|
||||||
|
{
|
||||||
|
return DictLoc.BUILT_IN == getDictLoc( context, name );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean moveDict( Context context, String name,
|
||||||
|
DictLoc from, DictLoc to )
|
||||||
|
{
|
||||||
|
boolean success;
|
||||||
|
name = addDictExtn( name );
|
||||||
|
|
||||||
|
File toPath = getDictFile( context, name, to );
|
||||||
|
if ( null != toPath && toPath.exists() ) {
|
||||||
|
success = false;
|
||||||
|
} else {
|
||||||
|
success = copyDict( context, name, from, to );
|
||||||
|
if ( success ) {
|
||||||
|
deleteDict( context, name, from );
|
||||||
|
s_dictListCache = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean copyDict( Context context, String name,
|
||||||
|
DictLoc from, DictLoc to )
|
||||||
|
{
|
||||||
|
boolean success = false;
|
||||||
|
|
||||||
|
File file = getSDPathFor( context, name );
|
||||||
|
if ( null != file ) {
|
||||||
|
FileChannel channelIn = null;
|
||||||
|
FileChannel channelOut = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
FileInputStream fis;
|
||||||
|
FileOutputStream fos;
|
||||||
|
if ( DictLoc.INTERNAL == from ) {
|
||||||
|
fis = context.openFileInput( name );
|
||||||
|
fos = new FileOutputStream( file );
|
||||||
|
} else {
|
||||||
|
fis = new FileInputStream( file );
|
||||||
|
fos = context.openFileOutput( name, Context.MODE_PRIVATE );
|
||||||
|
}
|
||||||
|
|
||||||
|
channelIn = fis.getChannel();
|
||||||
|
channelOut = fos.getChannel();
|
||||||
|
|
||||||
|
channelIn.transferTo( 0, channelIn.size(), channelOut );
|
||||||
|
success = true;
|
||||||
|
|
||||||
|
} catch ( java.io.FileNotFoundException fnfe ) {
|
||||||
|
Utils.logf( "%s", fnfe.toString() );
|
||||||
|
} catch ( java.io.IOException ioe ) {
|
||||||
|
Utils.logf( "%s", ioe.toString() );
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
// Order should match assignment order to above in
|
||||||
|
// case one or both null
|
||||||
|
channelIn.close();
|
||||||
|
channelOut.close();
|
||||||
|
} catch ( Exception e ) {
|
||||||
|
Utils.logf( "%s", e.toString() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
} // copyDict
|
||||||
|
|
||||||
|
public static void deleteDict( Context context, String name, DictLoc loc )
|
||||||
|
{
|
||||||
|
name = addDictExtn( name );
|
||||||
|
if ( DictLoc.EXTERNAL == loc ) {
|
||||||
|
File onSD = getSDPathFor( context, name );
|
||||||
|
if ( null != onSD ) {
|
||||||
|
onSD.delete();
|
||||||
|
} // otherwise what?
|
||||||
|
} else {
|
||||||
|
Assert.assertTrue( DictLoc.INTERNAL == loc );
|
||||||
|
context.deleteFile( name );
|
||||||
|
}
|
||||||
|
s_dictListCache = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void deleteDict( Context context, String name )
|
||||||
|
{
|
||||||
|
deleteDict( context, name, getDictLoc( context, name ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] openDict( Context context, String name, DictLoc loc )
|
||||||
|
{
|
||||||
|
byte[] bytes = null;
|
||||||
|
|
||||||
|
name = addDictExtn( name );
|
||||||
|
|
||||||
|
if ( loc == DictLoc.UNKNOWN || loc == DictLoc.BUILT_IN ) {
|
||||||
|
try {
|
||||||
|
AssetManager am = context.getAssets();
|
||||||
|
InputStream dict = am.open( name, android.content.res.
|
||||||
|
AssetManager.ACCESS_RANDOM );
|
||||||
|
|
||||||
|
int len = dict.available(); // this may not be the
|
||||||
|
// full length!
|
||||||
|
bytes = new byte[len];
|
||||||
|
int nRead = dict.read( bytes, 0, len );
|
||||||
|
if ( nRead != len ) {
|
||||||
|
Utils.logf( "**** warning ****; read only %d of %d bytes.",
|
||||||
|
nRead, len );
|
||||||
|
}
|
||||||
|
// check that with len bytes we've read the whole file
|
||||||
|
Assert.assertTrue( -1 == dict.read() );
|
||||||
|
} catch ( java.io.IOException ee ){
|
||||||
|
Utils.logf( "%s failed to open; likely not built-in", name );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// not an asset? Try external and internal storage
|
||||||
|
if ( null == bytes ) {
|
||||||
|
try {
|
||||||
|
FileInputStream fis = null;
|
||||||
|
if ( loc == DictLoc.UNKNOWN || loc == DictLoc.EXTERNAL ) {
|
||||||
|
File sdFile = getSDPathFor( context, name );
|
||||||
|
if ( null != sdFile && sdFile.exists() ) {
|
||||||
|
Utils.logf( "loading %s from SD", name );
|
||||||
|
fis = new FileInputStream( sdFile );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( null == fis ) {
|
||||||
|
if ( loc == DictLoc.UNKNOWN || loc == DictLoc.INTERNAL ) {
|
||||||
|
Utils.logf( "loading %s from private storage", name );
|
||||||
|
fis = context.openFileInput( name );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int len = (int)fis.getChannel().size();
|
||||||
|
bytes = new byte[len];
|
||||||
|
fis.read( bytes, 0, len );
|
||||||
|
fis.close();
|
||||||
|
Utils.logf( "Successfully loaded %s", name );
|
||||||
|
} catch ( java.io.FileNotFoundException fnf ) {
|
||||||
|
Utils.logf( fnf.toString() );
|
||||||
|
} catch ( java.io.IOException ioe ) {
|
||||||
|
Utils.logf( ioe.toString() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
} // openDict
|
||||||
|
|
||||||
|
private static byte[] openDict( Context context, String name )
|
||||||
|
{
|
||||||
|
return openDict( context, name, DictLoc.UNKNOWN );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getDictPath( Context context, String name )
|
||||||
|
{
|
||||||
|
name = addDictExtn( name );
|
||||||
|
|
||||||
|
File file = context.getFileStreamPath( name );
|
||||||
|
if ( !file.exists() ) {
|
||||||
|
file = getSDPathFor( context, name );
|
||||||
|
if ( null != file && !file.exists() ) {
|
||||||
|
file = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String path = null == file? null : file.getPath();
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static File getDictFile( Context context, String name, DictLoc to )
|
||||||
|
{
|
||||||
|
File path;
|
||||||
|
switch ( to ) {
|
||||||
|
case EXTERNAL:
|
||||||
|
path = getSDPathFor( context, name );
|
||||||
|
break;
|
||||||
|
case INTERNAL:
|
||||||
|
path = context.getFileStreamPath( name );
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Assert.fail();
|
||||||
|
path = null;
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DictPairs openDicts( Context context, String[] names )
|
||||||
|
{
|
||||||
|
byte[][] dictBytes = new byte[names.length][];
|
||||||
|
String[] dictPaths = new String[names.length];
|
||||||
|
|
||||||
|
HashMap<String,byte[]> seen = new HashMap<String,byte[]>();
|
||||||
|
for ( int ii = 0; ii < names.length; ++ii ) {
|
||||||
|
byte[] bytes = null;
|
||||||
|
String path = null;
|
||||||
|
String name = names[ii];
|
||||||
|
if ( null != name ) {
|
||||||
|
path = getDictPath( context, name );
|
||||||
|
if ( null == path ) {
|
||||||
|
bytes = seen.get( name );
|
||||||
|
if ( null == bytes ) {
|
||||||
|
bytes = openDict( context, name );
|
||||||
|
seen.put( name, bytes );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dictBytes[ii] = bytes;
|
||||||
|
dictPaths[ii] = path;
|
||||||
|
}
|
||||||
|
return new DictPairs( dictBytes, dictPaths );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean saveDict( Context context, InputStream in,
|
||||||
|
String name, DictLoc loc )
|
||||||
|
{
|
||||||
|
boolean success = false;
|
||||||
|
File sdFile = null;
|
||||||
|
boolean useSD = DictLoc.EXTERNAL == loc;
|
||||||
|
if ( useSD ) {
|
||||||
|
sdFile = getSDPathFor( context, name );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( null != sdFile || !useSD ) {
|
||||||
|
try {
|
||||||
|
FileOutputStream fos;
|
||||||
|
if ( null != sdFile ) {
|
||||||
|
fos = new FileOutputStream( sdFile );
|
||||||
|
} else {
|
||||||
|
fos = context.openFileOutput( name, Context.MODE_PRIVATE );
|
||||||
|
}
|
||||||
|
byte[] buf = new byte[1024];
|
||||||
|
int nRead;
|
||||||
|
while( 0 <= (nRead = in.read( buf, 0, buf.length )) ) {
|
||||||
|
fos.write( buf, 0, nRead );
|
||||||
|
}
|
||||||
|
fos.close();
|
||||||
|
s_dictListCache = null;
|
||||||
|
success = true;
|
||||||
|
} catch ( java.io.FileNotFoundException fnf ) {
|
||||||
|
Utils.logf( "saveDict: FileNotFoundException: %s",
|
||||||
|
fnf.toString() );
|
||||||
|
} catch ( java.io.IOException ioe ) {
|
||||||
|
Utils.logf( "saveDict: IOException: %s", ioe.toString() );
|
||||||
|
deleteDict( context, name );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isGame( String file )
|
||||||
|
{
|
||||||
|
return file.endsWith( XWConstants.GAME_EXTN );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isDict( String file )
|
||||||
|
{
|
||||||
|
return file.endsWith( XWConstants.DICT_EXTN );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String removeDictExtn( String str )
|
||||||
|
{
|
||||||
|
if ( str.endsWith( XWConstants.DICT_EXTN ) ) {
|
||||||
|
int indx = str.lastIndexOf( XWConstants.DICT_EXTN );
|
||||||
|
str = str.substring( 0, indx );
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String addDictExtn( String str )
|
||||||
|
{
|
||||||
|
if ( ! str.endsWith( XWConstants.DICT_EXTN ) ) {
|
||||||
|
str += XWConstants.DICT_EXTN;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String[] getAssets( Context context )
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
AssetManager am = context.getAssets();
|
||||||
|
return am.list("");
|
||||||
|
} catch( java.io.IOException ioe ) {
|
||||||
|
Utils.logf( ioe.toString() );
|
||||||
|
return new String[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean haveWriteableSD()
|
||||||
|
{
|
||||||
|
String state = Environment.getExternalStorageState();
|
||||||
|
|
||||||
|
return state.equals( Environment.MEDIA_MOUNTED );
|
||||||
|
// want this later? Environment.MEDIA_MOUNTED_READ_ONLY
|
||||||
|
}
|
||||||
|
|
||||||
|
private static File getSDDir( Context context )
|
||||||
|
{
|
||||||
|
File result = null;
|
||||||
|
if ( haveWriteableSD() ) {
|
||||||
|
File storage = Environment.getExternalStorageDirectory();
|
||||||
|
if ( null != storage ) {
|
||||||
|
String packdir = String.format( "Android/data/%s/files/",
|
||||||
|
context.getPackageName() );
|
||||||
|
result = new File( storage.getPath(), packdir );
|
||||||
|
if ( !result.exists() ) {
|
||||||
|
result.mkdirs();
|
||||||
|
if ( !result.exists() ) {
|
||||||
|
Utils.logf( "unable to create sd dir %s", packdir );
|
||||||
|
result = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static File getSDPathFor( Context context, String name )
|
||||||
|
{
|
||||||
|
File result = null;
|
||||||
|
File dir = getSDDir( context );
|
||||||
|
if ( dir != null ) {
|
||||||
|
result = new File( dir, name );
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -50,6 +50,7 @@ import android.preference.PreferenceManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import junit.framework.Assert;
|
import junit.framework.Assert;
|
||||||
|
|
||||||
|
import org.eehouse.android.xw4.DictUtils.DictAndLoc;
|
||||||
import org.eehouse.android.xw4.jni.XwJNI;
|
import org.eehouse.android.xw4.jni.XwJNI;
|
||||||
import org.eehouse.android.xw4.jni.JNIUtilsImpl;
|
import org.eehouse.android.xw4.jni.JNIUtilsImpl;
|
||||||
import org.eehouse.android.xw4.jni.CommonPrefs;
|
import org.eehouse.android.xw4.jni.CommonPrefs;
|
||||||
|
@ -85,8 +86,8 @@ public class DictsActivity extends ExpandableListActivity
|
||||||
private DictListAdapter m_adapter;
|
private DictListAdapter m_adapter;
|
||||||
|
|
||||||
private long m_packedPosition;
|
private long m_packedPosition;
|
||||||
private GameUtils.DictLoc m_moveFromLoc;
|
private DictUtils.DictLoc m_moveFromLoc;
|
||||||
private GameUtils.DictLoc m_moveToLoc;
|
private DictUtils.DictLoc m_moveToLoc;
|
||||||
private SDCardWatcher m_cardWatcher;
|
private SDCardWatcher m_cardWatcher;
|
||||||
|
|
||||||
private LayoutInflater m_factory;
|
private LayoutInflater m_factory;
|
||||||
|
@ -96,13 +97,12 @@ public class DictsActivity extends ExpandableListActivity
|
||||||
private XWListItem[][] m_cache;
|
private XWListItem[][] m_cache;
|
||||||
|
|
||||||
public DictListAdapter( Context context ) {
|
public DictListAdapter( Context context ) {
|
||||||
//super( context, m_dicts.length );
|
|
||||||
m_context = context;
|
m_context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean areAllItemsEnabled() { return false; }
|
public boolean areAllItemsEnabled() { return false; }
|
||||||
|
|
||||||
public Object getChild(int groupPosition, int childPosition)
|
public Object getChild( int groupPosition, int childPosition )
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -127,27 +127,27 @@ public class DictsActivity extends ExpandableListActivity
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( null == view ) {
|
if ( null == view ) {
|
||||||
int lang = (int)getGroupId( groupPosition );
|
view = (XWListItem)
|
||||||
String[] dicts = DictLangCache.getHaveLang( m_context, lang );
|
m_factory.inflate( R.layout.list_item, null );
|
||||||
String text;
|
|
||||||
boolean canDelete = false;
|
|
||||||
if ( null != dicts && childPosition < dicts.length ) {
|
|
||||||
text = dicts[childPosition];
|
|
||||||
canDelete = !GameUtils.dictIsBuiltin( DictsActivity.this,
|
|
||||||
text );
|
|
||||||
} else {
|
|
||||||
text = m_download;
|
|
||||||
}
|
|
||||||
view = (XWListItem)m_factory.inflate( R.layout.list_item, null );
|
|
||||||
view.setText( text );
|
|
||||||
if ( canDelete ) {
|
|
||||||
view.setDeleteCallback( DictsActivity.this );
|
|
||||||
}
|
|
||||||
|
|
||||||
GameUtils.DictLoc loc =
|
int lang = (int)getGroupId( groupPosition );
|
||||||
GameUtils.getDictLoc( DictsActivity.this, text );
|
DictAndLoc[] dals = DictLangCache.getDALsHaveLang( m_context,
|
||||||
|
lang );
|
||||||
|
|
||||||
|
if ( null != dals && childPosition < dals.length ) {
|
||||||
|
DictAndLoc dal;
|
||||||
|
dal = dals[childPosition];
|
||||||
|
view.setText( dal.name );
|
||||||
|
|
||||||
|
DictUtils.DictLoc loc = dal.loc;
|
||||||
view.setComment( m_locNames[loc.ordinal()] );
|
view.setComment( m_locNames[loc.ordinal()] );
|
||||||
view.cache( loc );
|
view.cache( loc );
|
||||||
|
if ( DictUtils.DictLoc.BUILT_IN != loc ) {
|
||||||
|
view.setDeleteCallback( DictsActivity.this );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
view.setText( m_download );
|
||||||
|
}
|
||||||
|
|
||||||
addToCache( groupPosition, childPosition, view );
|
addToCache( groupPosition, childPosition, view );
|
||||||
}
|
}
|
||||||
|
@ -157,10 +157,10 @@ public class DictsActivity extends ExpandableListActivity
|
||||||
public int getChildrenCount( int groupPosition )
|
public int getChildrenCount( int groupPosition )
|
||||||
{
|
{
|
||||||
int lang = (int)getGroupId( groupPosition );
|
int lang = (int)getGroupId( groupPosition );
|
||||||
String[] dicts = DictLangCache.getHaveLang( m_context, lang );
|
DictAndLoc[] dals = DictLangCache.getDALsHaveLang( m_context, lang );
|
||||||
int result = 0; // 1; // 1 for the download option
|
int result = 0; // 1; // 1 for the download option
|
||||||
if ( null != dicts ) {
|
if ( null != dals ) {
|
||||||
result += dicts.length;
|
result += dals.length;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -263,7 +263,7 @@ public class DictsActivity extends ExpandableListActivity
|
||||||
lstnr = new DialogInterface.OnClickListener() {
|
lstnr = new DialogInterface.OnClickListener() {
|
||||||
public void onClick( DialogInterface dlg, int item ) {
|
public void onClick( DialogInterface dlg, int item ) {
|
||||||
XWListItem rowView = m_adapter.getSelChildView();
|
XWListItem rowView = m_adapter.getSelChildView();
|
||||||
if ( GameUtils.moveDict( DictsActivity.this,
|
if ( DictUtils.moveDict( DictsActivity.this,
|
||||||
rowView.getText(),
|
rowView.getText(),
|
||||||
m_moveFromLoc,
|
m_moveFromLoc,
|
||||||
m_moveToLoc ) ) {
|
m_moveToLoc ) ) {
|
||||||
|
@ -408,11 +408,11 @@ public class DictsActivity extends ExpandableListActivity
|
||||||
|
|
||||||
int tmp = savedInstanceState.getInt( MOVEFROMLOC, -1 );
|
int tmp = savedInstanceState.getInt( MOVEFROMLOC, -1 );
|
||||||
if ( -1 != tmp ) {
|
if ( -1 != tmp ) {
|
||||||
m_moveFromLoc = GameUtils.DictLoc.values()[tmp];
|
m_moveFromLoc = DictUtils.DictLoc.values()[tmp];
|
||||||
}
|
}
|
||||||
tmp = savedInstanceState.getInt( MOVETOLOC, -1 );
|
tmp = savedInstanceState.getInt( MOVETOLOC, -1 );
|
||||||
if ( -1 != tmp ) {
|
if ( -1 != tmp ) {
|
||||||
m_moveToLoc = GameUtils.DictLoc.values()[tmp];
|
m_moveToLoc = DictUtils.DictLoc.values()[tmp];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -452,9 +452,9 @@ public class DictsActivity extends ExpandableListActivity
|
||||||
inflater.inflate( R.menu.dicts_item_menu, menu );
|
inflater.inflate( R.menu.dicts_item_menu, menu );
|
||||||
|
|
||||||
XWListItem row = (XWListItem)info.targetView;
|
XWListItem row = (XWListItem)info.targetView;
|
||||||
GameUtils.DictLoc loc = (GameUtils.DictLoc)row.getCached();
|
DictUtils.DictLoc loc = (DictUtils.DictLoc)row.getCached();
|
||||||
if ( loc == GameUtils.DictLoc.BUILT_IN
|
if ( loc == DictUtils.DictLoc.BUILT_IN
|
||||||
|| ! GameUtils.haveWriteableSD() ) {
|
|| ! DictUtils.haveWriteableSD() ) {
|
||||||
menu.removeItem( R.id.dicts_item_move );
|
menu.removeItem( R.id.dicts_item_move );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -510,34 +510,54 @@ public class DictsActivity extends ExpandableListActivity
|
||||||
// options for YY?
|
// options for YY?
|
||||||
private void askMoveDict( XWListItem item )
|
private void askMoveDict( XWListItem item )
|
||||||
{
|
{
|
||||||
m_moveFromLoc = (GameUtils.DictLoc)item.getCached();
|
m_moveFromLoc = (DictUtils.DictLoc)item.getCached();
|
||||||
if ( m_moveFromLoc == GameUtils.DictLoc.INTERNAL ) {
|
if ( m_moveFromLoc == DictUtils.DictLoc.INTERNAL ) {
|
||||||
m_moveToLoc = GameUtils.DictLoc.EXTERNAL;
|
m_moveToLoc = DictUtils.DictLoc.EXTERNAL;
|
||||||
} else {
|
} else {
|
||||||
m_moveToLoc = GameUtils.DictLoc.INTERNAL;
|
m_moveToLoc = DictUtils.DictLoc.INTERNAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
showDialog( MOVE_DICT );
|
showDialog( MOVE_DICT );
|
||||||
}
|
}
|
||||||
|
|
||||||
// XWListItem.DeleteCallback interface
|
// XWListItem.DeleteCallback interface
|
||||||
public void deleteCalled( int myPosition, String dict )
|
public void deleteCalled( XWListItem item )
|
||||||
{
|
{
|
||||||
int code = DictLangCache.getDictLangCode( this, dict );
|
String dict = item.getText();
|
||||||
String lang = DictLangCache.getLangName( this, code );
|
|
||||||
int nGames = DBUtils.countGamesUsing( this, code );
|
|
||||||
String msg = String.format( getString( R.string.confirm_delete_dictf ),
|
String msg = String.format( getString( R.string.confirm_delete_dictf ),
|
||||||
dict );
|
dict );
|
||||||
m_deleteDict = dict;
|
|
||||||
|
|
||||||
if ( nGames > 0 ) {
|
m_deleteDict = dict;
|
||||||
int fmt;
|
m_moveFromLoc = (DictUtils.DictLoc)item.getCached();
|
||||||
if ( 1 == DictLangCache.getHaveLang( this, code ).length ) {
|
|
||||||
fmt = R.string.confirm_deleteonly_dictf;
|
// When and what to warn about. First off, if there's another
|
||||||
|
// identical dict, simply confirm. Or if nobody's using this
|
||||||
|
// dict *and* it's not the last of a language that somebody's
|
||||||
|
// using, simply confirm. If somebody is using it, then we
|
||||||
|
// want different warnings depending on whether it's the last
|
||||||
|
// available dict in its language.
|
||||||
|
|
||||||
|
if ( 1 < DictLangCache.getDictCount( this, dict ) ) {
|
||||||
|
// there's another; do nothing
|
||||||
} else {
|
} else {
|
||||||
fmt = R.string.confirm_deletemore_dictf;
|
int fmtid = 0;
|
||||||
|
int langcode = DictLangCache.getDictLangCode( this, dict );
|
||||||
|
DictAndLoc[] langDals = DictLangCache.getDALsHaveLang( this,
|
||||||
|
langcode );
|
||||||
|
int nUsingLang = DBUtils.countGamesUsingLang( this, langcode );
|
||||||
|
|
||||||
|
if ( 1 == langDals.length ) { // last in this language?
|
||||||
|
if ( 0 < nUsingLang ) {
|
||||||
|
fmtid = R.string.confirm_deleteonly_dictf;
|
||||||
|
}
|
||||||
|
} else if ( 0 < DBUtils.countGamesUsingDict( this, dict ) ) {
|
||||||
|
fmtid = R.string.confirm_deletemore_dictf;
|
||||||
|
}
|
||||||
|
if ( 0 != fmtid ) {
|
||||||
|
String fmt = getString( fmtid );
|
||||||
|
msg += String.format( fmt, DictLangCache.
|
||||||
|
getLangName( this, langcode ) );
|
||||||
}
|
}
|
||||||
msg += String.format( getString(fmt), lang );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_delegate.showConfirmThen( msg, DELETE_DICT_ACTION );
|
m_delegate.showConfirmThen( msg, DELETE_DICT_ACTION );
|
||||||
|
@ -556,7 +576,7 @@ public class DictsActivity extends ExpandableListActivity
|
||||||
switch( id ) {
|
switch( id ) {
|
||||||
case DELETE_DICT_ACTION:
|
case DELETE_DICT_ACTION:
|
||||||
if ( DialogInterface.BUTTON_POSITIVE == which ) {
|
if ( DialogInterface.BUTTON_POSITIVE == which ) {
|
||||||
deleteDict( m_deleteDict );
|
deleteDict( m_deleteDict, m_moveFromLoc );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -564,16 +584,16 @@ public class DictsActivity extends ExpandableListActivity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deleteDict( String dict )
|
private void deleteDict( String dict, DictUtils.DictLoc loc )
|
||||||
{
|
{
|
||||||
GameUtils.deleteDict( this, dict );
|
DictUtils.deleteDict( this, dict, loc );
|
||||||
DictLangCache.inval( this, dict, false );
|
DictLangCache.inval( this, dict, loc, false );
|
||||||
mkListAdapter();
|
mkListAdapter();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void askStartDownload( int lang, String name )
|
private void askStartDownload( int lang, String name )
|
||||||
{
|
{
|
||||||
if ( GameUtils.haveWriteableSD() ) {
|
if ( DictUtils.haveWriteableSD() ) {
|
||||||
m_lang = lang;
|
m_lang = lang;
|
||||||
m_name = name;
|
m_name = name;
|
||||||
showDialog( PICK_STORAGE );
|
showDialog( PICK_STORAGE );
|
||||||
|
|
|
@ -533,9 +533,9 @@ public class GameConfig extends XWActivity
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteCallback interface
|
// DeleteCallback interface
|
||||||
public void deleteCalled( int myPosition, final String name )
|
public void deleteCalled( XWListItem item )
|
||||||
{
|
{
|
||||||
if ( m_gi.delete( myPosition ) ) {
|
if ( m_gi.delete( item.getPosition() ) ) {
|
||||||
loadPlayersList();
|
loadPlayersList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,6 @@ import org.eehouse.android.xw4.jni.CurGameInfo.DeviceRole;
|
||||||
|
|
||||||
public class GameUtils {
|
public class GameUtils {
|
||||||
|
|
||||||
public enum DictLoc { BUILT_IN, INTERNAL, EXTERNAL, DOWNLOAD };
|
|
||||||
public static final String INVITED = "invited";
|
public static final String INVITED = "invited";
|
||||||
|
|
||||||
// Implements read-locks and write-locks per game. A read lock is
|
// Implements read-locks and write-locks per game. A read lock is
|
||||||
|
@ -152,30 +151,6 @@ public class GameUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class DictPairs {
|
|
||||||
public byte[][] m_bytes;
|
|
||||||
public String[] m_paths;
|
|
||||||
public DictPairs( byte[][] bytes, String[] paths ) {
|
|
||||||
m_bytes = bytes; m_paths = paths;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean anyMissing( final String[] names )
|
|
||||||
{
|
|
||||||
boolean missing = false;
|
|
||||||
for ( int ii = 0; ii < m_paths.length; ++ii ) {
|
|
||||||
if ( names[ii] != null ) {
|
|
||||||
// It's ok for there to be no dict IFF there's no
|
|
||||||
// name. That's a player using the default dict.
|
|
||||||
if ( null == m_paths[ii] && null == m_bytes[ii] ) {
|
|
||||||
missing = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return missing;
|
|
||||||
}
|
|
||||||
} // DictPairs
|
|
||||||
|
|
||||||
private static Object s_syncObj = new Object();
|
private static Object s_syncObj = new Object();
|
||||||
|
|
||||||
public static byte[] savedGame( Context context, long rowid )
|
public static byte[] savedGame( Context context, long rowid )
|
||||||
|
@ -205,7 +180,7 @@ public class GameUtils {
|
||||||
// as DeviceRole.SERVER_STANDALONE != gi.serverRole
|
// as DeviceRole.SERVER_STANDALONE != gi.serverRole
|
||||||
int gamePtr = loadMakeGame( context, gi, lockSrc );
|
int gamePtr = loadMakeGame( context, gi, lockSrc );
|
||||||
String[] dictNames = gi.dictNames();
|
String[] dictNames = gi.dictNames();
|
||||||
DictPairs pairs = openDicts( context, dictNames );
|
DictUtils.DictPairs pairs = DictUtils.openDicts( context, dictNames );
|
||||||
|
|
||||||
if ( XwJNI.game_hasComms( gamePtr ) ) {
|
if ( XwJNI.game_hasComms( gamePtr ) ) {
|
||||||
addr = new CommsAddrRec( context );
|
addr = new CommsAddrRec( context );
|
||||||
|
@ -334,7 +309,7 @@ public class GameUtils {
|
||||||
byte[] stream = savedGame( context, lock );
|
byte[] stream = savedGame( context, lock );
|
||||||
XwJNI.gi_from_stream( gi, stream );
|
XwJNI.gi_from_stream( gi, stream );
|
||||||
String[] dictNames = gi.dictNames();
|
String[] dictNames = gi.dictNames();
|
||||||
DictPairs pairs = openDicts( context, dictNames );
|
DictUtils.DictPairs pairs = DictUtils.openDicts( context, dictNames );
|
||||||
if ( pairs.anyMissing( dictNames ) ) {
|
if ( pairs.anyMissing( dictNames ) ) {
|
||||||
Utils.logf( "loadMakeGame() failing: dict unavailable" );
|
Utils.logf( "loadMakeGame() failing: dict unavailable" );
|
||||||
} else {
|
} else {
|
||||||
|
@ -491,11 +466,13 @@ public class GameUtils {
|
||||||
{
|
{
|
||||||
String[] dictNames = dictNames( context, rowid, missingLang );
|
String[] dictNames = dictNames( context, rowid, missingLang );
|
||||||
HashSet<String> missingSet;
|
HashSet<String> missingSet;
|
||||||
String[] installed = dictList( context );
|
DictUtils.DictAndLoc[] installed = DictUtils.dictList( context );
|
||||||
|
|
||||||
missingSet = new HashSet<String>( Arrays.asList( dictNames ) );
|
missingSet = new HashSet<String>( Arrays.asList( dictNames ) );
|
||||||
missingSet.remove( null );
|
missingSet.remove( null );
|
||||||
missingSet.removeAll( Arrays.asList(installed) );
|
for ( DictUtils.DictAndLoc dal : installed ) {
|
||||||
|
missingSet.remove( dal.name );
|
||||||
|
}
|
||||||
boolean allHere = 0 == missingSet.size();
|
boolean allHere = 0 == missingSet.size();
|
||||||
if ( null != missingNames ) {
|
if ( null != missingNames ) {
|
||||||
missingNames[0] =
|
missingNames[0] =
|
||||||
|
@ -533,288 +510,11 @@ public class GameUtils {
|
||||||
// return name;
|
// return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String[] dictList( Context context )
|
|
||||||
{
|
|
||||||
ArrayList<String> al = new ArrayList<String>();
|
|
||||||
|
|
||||||
for ( String file : getAssets( context ) ) {
|
|
||||||
if ( isDict( file ) ) {
|
|
||||||
al.add( removeDictExtn( file ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( String file : context.fileList() ) {
|
|
||||||
if ( isDict( file ) ) {
|
|
||||||
al.add( removeDictExtn( file ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
File sdDir = getSDDir( context );
|
|
||||||
if ( null != sdDir ) {
|
|
||||||
for ( String file : sdDir.list() ) {
|
|
||||||
if ( isDict( file ) ) {
|
|
||||||
al.add( removeDictExtn( file ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return al.toArray( new String[al.size()] );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DictLoc getDictLoc( Context context, String name )
|
|
||||||
{
|
|
||||||
DictLoc loc = null;
|
|
||||||
name = addDictExtn( name );
|
|
||||||
|
|
||||||
for ( String file : getAssets( context ) ) {
|
|
||||||
if ( file.equals( name ) ) {
|
|
||||||
loc = DictLoc.BUILT_IN;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( null == loc ) {
|
|
||||||
try {
|
|
||||||
FileInputStream fis = context.openFileInput( name );
|
|
||||||
fis.close();
|
|
||||||
loc = DictLoc.INTERNAL;
|
|
||||||
} catch ( java.io.FileNotFoundException fnf ) {
|
|
||||||
} catch ( java.io.IOException ioe ) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( null == loc ) {
|
|
||||||
File file = getSDPathFor( context, name );
|
|
||||||
if ( null != file && file.exists() ) {
|
|
||||||
loc = DictLoc.EXTERNAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return loc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean dictExists( Context context, String name )
|
|
||||||
{
|
|
||||||
return null != getDictLoc( context, name );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean dictIsBuiltin( Context context, String name )
|
|
||||||
{
|
|
||||||
return DictLoc.BUILT_IN == getDictLoc( context, name );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean moveDict( Context context, String name,
|
|
||||||
DictLoc from, DictLoc to )
|
|
||||||
{
|
|
||||||
name = addDictExtn( name );
|
|
||||||
boolean success = copyDict( context, name, from, to );
|
|
||||||
if ( success ) {
|
|
||||||
deleteDict( context, name, from );
|
|
||||||
}
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean copyDict( Context context, String name,
|
|
||||||
DictLoc from, DictLoc to )
|
|
||||||
{
|
|
||||||
boolean success = false;
|
|
||||||
|
|
||||||
File file = getSDPathFor( context, name );
|
|
||||||
if ( null != file ) {
|
|
||||||
FileChannel channelIn = null;
|
|
||||||
FileChannel channelOut = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
FileInputStream fis;
|
|
||||||
FileOutputStream fos;
|
|
||||||
if ( DictLoc.INTERNAL == from ) {
|
|
||||||
fis = context.openFileInput( name );
|
|
||||||
fos = new FileOutputStream( file );
|
|
||||||
} else {
|
|
||||||
fis = new FileInputStream( file );
|
|
||||||
fos = context.openFileOutput( name, Context.MODE_PRIVATE );
|
|
||||||
}
|
|
||||||
|
|
||||||
channelIn = fis.getChannel();
|
|
||||||
channelOut = fos.getChannel();
|
|
||||||
|
|
||||||
channelIn.transferTo( 0, channelIn.size(), channelOut );
|
|
||||||
success = true;
|
|
||||||
|
|
||||||
} catch ( java.io.FileNotFoundException fnfe ) {
|
|
||||||
Utils.logf( "%s", fnfe.toString() );
|
|
||||||
} catch ( java.io.IOException ioe ) {
|
|
||||||
Utils.logf( "%s", ioe.toString() );
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
// Order should match assignment order to above in
|
|
||||||
// case one or both null
|
|
||||||
channelIn.close();
|
|
||||||
channelOut.close();
|
|
||||||
} catch ( Exception e ) {
|
|
||||||
Utils.logf( "%s", e.toString() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return success;
|
|
||||||
} // copyDict
|
|
||||||
|
|
||||||
private static void deleteDict( Context context, String name, DictLoc loc )
|
|
||||||
{
|
|
||||||
if ( DictLoc.EXTERNAL == loc ) {
|
|
||||||
File onSD = getSDPathFor( context, name );
|
|
||||||
if ( null != onSD ) {
|
|
||||||
onSD.delete();
|
|
||||||
} // otherwise what?
|
|
||||||
} else {
|
|
||||||
Assert.assertTrue( DictLoc.INTERNAL == loc );
|
|
||||||
context.deleteFile( name );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void deleteDict( Context context, String name )
|
|
||||||
{
|
|
||||||
name = addDictExtn( name );
|
|
||||||
deleteDict( context, name, getDictLoc( context, name ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] openDict( Context context, String name )
|
|
||||||
{
|
|
||||||
byte[] bytes = null;
|
|
||||||
|
|
||||||
name = addDictExtn( name );
|
|
||||||
|
|
||||||
try {
|
|
||||||
AssetManager am = context.getAssets();
|
|
||||||
InputStream dict = am.open( name,
|
|
||||||
android.content.res.AssetManager.ACCESS_RANDOM );
|
|
||||||
|
|
||||||
int len = dict.available(); // this may not be the full length!
|
|
||||||
bytes = new byte[len];
|
|
||||||
int nRead = dict.read( bytes, 0, len );
|
|
||||||
if ( nRead != len ) {
|
|
||||||
Utils.logf( "**** warning ****; read only %d of %d bytes.",
|
|
||||||
nRead, len );
|
|
||||||
}
|
|
||||||
// check that with len bytes we've read the whole file
|
|
||||||
Assert.assertTrue( -1 == dict.read() );
|
|
||||||
} catch ( java.io.IOException ee ){
|
|
||||||
Utils.logf( "%s failed to open; likely not built-in", name );
|
|
||||||
}
|
|
||||||
|
|
||||||
// not an asset? Try external and internal storage
|
|
||||||
if ( null == bytes ) {
|
|
||||||
try {
|
|
||||||
File sdFile = getSDPathFor( context, name );
|
|
||||||
FileInputStream fis;
|
|
||||||
if ( null != sdFile && sdFile.exists() ) {
|
|
||||||
Utils.logf( "loading %s from SD", name );
|
|
||||||
fis = new FileInputStream( sdFile );
|
|
||||||
} else {
|
|
||||||
Utils.logf( "loading %s from private storage", name );
|
|
||||||
fis = context.openFileInput( name );
|
|
||||||
}
|
|
||||||
int len = (int)fis.getChannel().size();
|
|
||||||
bytes = new byte[len];
|
|
||||||
fis.read( bytes, 0, len );
|
|
||||||
fis.close();
|
|
||||||
Utils.logf( "Successfully loaded %s", name );
|
|
||||||
} catch ( java.io.FileNotFoundException fnf ) {
|
|
||||||
Utils.logf( fnf.toString() );
|
|
||||||
} catch ( java.io.IOException ioe ) {
|
|
||||||
Utils.logf( ioe.toString() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getDictPath( Context context, String name )
|
|
||||||
{
|
|
||||||
name = addDictExtn( name );
|
|
||||||
|
|
||||||
File file = context.getFileStreamPath( name );
|
|
||||||
if ( !file.exists() ) {
|
|
||||||
file = getSDPathFor( context, name );
|
|
||||||
if ( null != file && !file.exists() ) {
|
|
||||||
file = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String path = null == file? null : file.getPath();
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DictPairs openDicts( Context context, String[] names )
|
|
||||||
{
|
|
||||||
byte[][] dictBytes = new byte[names.length][];
|
|
||||||
String[] dictPaths = new String[names.length];
|
|
||||||
|
|
||||||
HashMap<String,byte[]> seen = new HashMap<String,byte[]>();
|
|
||||||
for ( int ii = 0; ii < names.length; ++ii ) {
|
|
||||||
byte[] bytes = null;
|
|
||||||
String path = null;
|
|
||||||
String name = names[ii];
|
|
||||||
if ( null != name ) {
|
|
||||||
path = getDictPath( context, name );
|
|
||||||
if ( null == path ) {
|
|
||||||
bytes = seen.get( name );
|
|
||||||
if ( null == bytes ) {
|
|
||||||
bytes = openDict( context, name );
|
|
||||||
seen.put( name, bytes );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dictBytes[ii] = bytes;
|
|
||||||
dictPaths[ii] = path;
|
|
||||||
}
|
|
||||||
return new DictPairs( dictBytes, dictPaths );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean saveDict( Context context, InputStream in,
|
|
||||||
String name, boolean useSD )
|
|
||||||
{
|
|
||||||
boolean success = false;
|
|
||||||
File sdFile = null;
|
|
||||||
if ( useSD ) {
|
|
||||||
sdFile = getSDPathFor( context, name );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( null != sdFile || !useSD ) {
|
|
||||||
try {
|
|
||||||
FileOutputStream fos;
|
|
||||||
if ( null != sdFile ) {
|
|
||||||
fos = new FileOutputStream( sdFile );
|
|
||||||
} else {
|
|
||||||
fos = context.openFileOutput( name, Context.MODE_PRIVATE );
|
|
||||||
}
|
|
||||||
byte[] buf = new byte[1024];
|
|
||||||
int nRead;
|
|
||||||
while( 0 <= (nRead = in.read( buf, 0, buf.length )) ) {
|
|
||||||
fos.write( buf, 0, nRead );
|
|
||||||
}
|
|
||||||
fos.close();
|
|
||||||
success = true;
|
|
||||||
} catch ( java.io.FileNotFoundException fnf ) {
|
|
||||||
Utils.logf( "saveDict: FileNotFoundException: %s",
|
|
||||||
fnf.toString() );
|
|
||||||
} catch ( java.io.IOException ioe ) {
|
|
||||||
Utils.logf( "saveDict: IOException: %s", ioe.toString() );
|
|
||||||
deleteDict( context, name );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isGame( String file )
|
private static boolean isGame( String file )
|
||||||
{
|
{
|
||||||
return file.endsWith( XWConstants.GAME_EXTN );
|
return file.endsWith( XWConstants.GAME_EXTN );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isDict( String file )
|
|
||||||
{
|
|
||||||
return file.endsWith( XWConstants.DICT_EXTN );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void launchGame( Activity activity, long rowid,
|
public static void launchGame( Activity activity, long rowid,
|
||||||
boolean invited )
|
boolean invited )
|
||||||
{
|
{
|
||||||
|
@ -931,7 +631,7 @@ public class GameUtils {
|
||||||
gi.replaceDicts( newDict );
|
gi.replaceDicts( newDict );
|
||||||
|
|
||||||
String[] dictNames = gi.dictNames();
|
String[] dictNames = gi.dictNames();
|
||||||
DictPairs pairs = openDicts( context, dictNames );
|
DictUtils.DictPairs pairs = DictUtils.openDicts( context, dictNames );
|
||||||
|
|
||||||
int gamePtr = XwJNI.initJNI();
|
int gamePtr = XwJNI.initJNI();
|
||||||
XwJNI.game_makeFromStream( gamePtr, stream, gi, dictNames,
|
XwJNI.game_makeFromStream( gamePtr, stream, gi, dictNames,
|
||||||
|
@ -957,7 +657,7 @@ public class GameUtils {
|
||||||
// that don't reset the game, e.g. player name for standalone
|
// that don't reset the game, e.g. player name for standalone
|
||||||
// games?
|
// games?
|
||||||
String[] dictNames = gi.dictNames();
|
String[] dictNames = gi.dictNames();
|
||||||
DictPairs pairs = openDicts( context, dictNames );
|
DictUtils.DictPairs pairs = DictUtils.openDicts( context, dictNames );
|
||||||
String langName = gi.langName();
|
String langName = gi.langName();
|
||||||
int gamePtr = XwJNI.initJNI();
|
int gamePtr = XwJNI.initJNI();
|
||||||
boolean madeGame = false;
|
boolean madeGame = false;
|
||||||
|
@ -1002,34 +702,6 @@ public class GameUtils {
|
||||||
activity.startActivity( intent );
|
activity.startActivity( intent );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String removeDictExtn( String str )
|
|
||||||
{
|
|
||||||
if ( str.endsWith( XWConstants.DICT_EXTN ) ) {
|
|
||||||
int indx = str.lastIndexOf( XWConstants.DICT_EXTN );
|
|
||||||
str = str.substring( 0, indx );
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String addDictExtn( String str )
|
|
||||||
{
|
|
||||||
if ( ! str.endsWith( XWConstants.DICT_EXTN ) ) {
|
|
||||||
str += XWConstants.DICT_EXTN;
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String[] getAssets( Context context )
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
AssetManager am = context.getAssets();
|
|
||||||
return am.list("");
|
|
||||||
} catch( java.io.IOException ioe ) {
|
|
||||||
Utils.logf( ioe.toString() );
|
|
||||||
return new String[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void tellRelayDied( Context context, GameLock lock,
|
private static void tellRelayDied( Context context, GameLock lock,
|
||||||
boolean informNow )
|
boolean informNow )
|
||||||
{
|
{
|
||||||
|
@ -1042,43 +714,5 @@ public class GameUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean haveWriteableSD()
|
|
||||||
{
|
|
||||||
String state = Environment.getExternalStorageState();
|
|
||||||
|
|
||||||
return state.equals( Environment.MEDIA_MOUNTED );
|
|
||||||
// want this later? Environment.MEDIA_MOUNTED_READ_ONLY
|
|
||||||
}
|
|
||||||
|
|
||||||
private static File getSDDir( Context context )
|
|
||||||
{
|
|
||||||
File result = null;
|
|
||||||
if ( haveWriteableSD() ) {
|
|
||||||
File storage = Environment.getExternalStorageDirectory();
|
|
||||||
if ( null != storage ) {
|
|
||||||
String packdir = String.format( "Android/data/%s/files/",
|
|
||||||
context.getPackageName() );
|
|
||||||
result = new File( storage.getPath(), packdir );
|
|
||||||
if ( !result.exists() ) {
|
|
||||||
result.mkdirs();
|
|
||||||
if ( !result.exists() ) {
|
|
||||||
Utils.logf( "unable to create sd dir %s", packdir );
|
|
||||||
result = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static File getSDPathFor( Context context, String name )
|
|
||||||
{
|
|
||||||
File result = null;
|
|
||||||
File dir = getSDDir( context );
|
|
||||||
if ( dir != null ) {
|
|
||||||
result = new File( dir, name );
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ public class XWListItem extends LinearLayout {
|
||||||
DeleteCallback m_cb;
|
DeleteCallback m_cb;
|
||||||
|
|
||||||
public interface DeleteCallback {
|
public interface DeleteCallback {
|
||||||
void deleteCalled( int myPosition, String name );
|
void deleteCalled( XWListItem item );
|
||||||
}
|
}
|
||||||
|
|
||||||
public XWListItem( Context cx, AttributeSet as ) {
|
public XWListItem( Context cx, AttributeSet as ) {
|
||||||
|
@ -72,7 +72,7 @@ public class XWListItem extends LinearLayout {
|
||||||
button.setOnClickListener( new View.OnClickListener() {
|
button.setOnClickListener( new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick( View view ) {
|
public void onClick( View view ) {
|
||||||
m_cb.deleteCalled( m_position, getText() );
|
m_cb.deleteCalled( XWListItem.this );
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
button.setVisibility( View.VISIBLE );
|
button.setVisibility( View.VISIBLE );
|
||||||
|
|
|
@ -29,7 +29,7 @@ import junit.framework.Assert;
|
||||||
|
|
||||||
import org.eehouse.android.xw4.Utils;
|
import org.eehouse.android.xw4.Utils;
|
||||||
import org.eehouse.android.xw4.R;
|
import org.eehouse.android.xw4.R;
|
||||||
import org.eehouse.android.xw4.GameUtils;
|
import org.eehouse.android.xw4.DictUtils;
|
||||||
|
|
||||||
public class CommonPrefs {
|
public class CommonPrefs {
|
||||||
public static final int COLOR_TILE_BACK = 0;
|
public static final int COLOR_TILE_BACK = 0;
|
||||||
|
@ -211,8 +211,8 @@ public class CommonPrefs {
|
||||||
public static String getDefaultHumanDict( Context context )
|
public static String getDefaultHumanDict( Context context )
|
||||||
{
|
{
|
||||||
String value = getString( context, R.string.key_default_dict );
|
String value = getString( context, R.string.key_default_dict );
|
||||||
if ( value.equals("") || !GameUtils.dictExists( context, value ) ) {
|
if ( value.equals("") || !DictUtils.dictExists( context, value ) ) {
|
||||||
value = GameUtils.dictList( context )[0];
|
value = DictUtils.dictList( context )[0].name;
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
@ -220,7 +220,7 @@ public class CommonPrefs {
|
||||||
public static String getDefaultRobotDict( Context context )
|
public static String getDefaultRobotDict( Context context )
|
||||||
{
|
{
|
||||||
String value = getString( context, R.string.key_default_robodict );
|
String value = getString( context, R.string.key_default_robodict );
|
||||||
if ( value.equals("") || !GameUtils.dictExists( context, value ) ) {
|
if ( value.equals("") || !DictUtils.dictExists( context, value ) ) {
|
||||||
value = getDefaultHumanDict( context );
|
value = getDefaultHumanDict( context );
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
|
|
|
@ -27,7 +27,7 @@ import java.util.Arrays;
|
||||||
import junit.framework.Assert;
|
import junit.framework.Assert;
|
||||||
|
|
||||||
import org.eehouse.android.xw4.Utils;
|
import org.eehouse.android.xw4.Utils;
|
||||||
import org.eehouse.android.xw4.GameUtils;
|
import org.eehouse.android.xw4.DictUtils;
|
||||||
import org.eehouse.android.xw4.R;
|
import org.eehouse.android.xw4.R;
|
||||||
import org.eehouse.android.xw4.DictLangCache;
|
import org.eehouse.android.xw4.DictLangCache;
|
||||||
|
|
||||||
|
@ -403,7 +403,7 @@ public class CurGameInfo {
|
||||||
DictLangCache.getBestDefault( m_context, dictLang, false );
|
DictLangCache.getBestDefault( m_context, dictLang, false );
|
||||||
|
|
||||||
if ( null == dictName
|
if ( null == dictName
|
||||||
|| ! GameUtils.dictExists( m_context, dictName )
|
|| ! DictUtils.dictExists( m_context, dictName )
|
||||||
|| dictLang != DictLangCache.getDictLangCode( m_context,
|
|| dictLang != DictLangCache.getDictLangCode( m_context,
|
||||||
dictName ) ) {
|
dictName ) ) {
|
||||||
dictName = humanDict;
|
dictName = humanDict;
|
||||||
|
|
|
@ -258,4 +258,14 @@ public class GameSummary {
|
||||||
return indx == turn && isLocal(indx);
|
return indx == turn && isLocal(indx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String dictNames( String separator )
|
||||||
|
{
|
||||||
|
String list = null;
|
||||||
|
if ( null != m_gi ) {
|
||||||
|
String[] names = m_gi.dictNames();
|
||||||
|
list = TextUtils.join( separator, names );
|
||||||
|
}
|
||||||
|
return String.format( "%s%s%s", separator, list, separator );
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue