From ce8104f679b2ba8d760905c5e6f32597199a2331 Mon Sep 17 00:00:00 2001 From: Andy2 Date: Tue, 6 Sep 2011 07:18:45 -0700 Subject: [PATCH] move dict-related methods from GameUtils.java to new DictUtils.java --- .../eehouse/android/xw4/BoardActivity.java | 2 +- .../android/xw4/DictImportActivity.java | 2 +- .../eehouse/android/xw4/DictLangCache.java | 12 +- .../android/xw4/DictListPreference.java | 2 +- .../org/eehouse/android/xw4/DictUtils.java | 426 ++++++++++++++++++ .../eehouse/android/xw4/DictsActivity.java | 40 +- .../org/eehouse/android/xw4/GameUtils.java | 378 +--------------- .../eehouse/android/xw4/jni/CommonPrefs.java | 8 +- .../eehouse/android/xw4/jni/CurGameInfo.java | 4 +- 9 files changed, 466 insertions(+), 408 deletions(-) create mode 100644 xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java index 9d207ba5b..cc3da1713 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java @@ -1170,7 +1170,7 @@ public class BoardActivity extends XWActivity { if ( 0 == m_jniGamePtr ) { 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 ) ) { showDictGoneFinish(); diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictImportActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictImportActivity.java index 34155b7ec..eaf5a8141 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictImportActivity.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictImportActivity.java @@ -121,7 +121,7 @@ public class DictImportActivity extends XWActivity { private String saveDict( InputStream inputStream, String path ) { String name = basename( path ); - if ( GameUtils.saveDict( this, inputStream, name, s_useSD ) ) { + if ( DictUtils.saveDict( this, inputStream, name, s_useSD ) ) { return name; } else { return null; diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictLangCache.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictLangCache.java index 3f293bdc0..d36733642 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictLangCache.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictLangCache.java @@ -95,7 +95,7 @@ public class DictLangCache { public static int getLangCount( Context context, int code ) { int count = 0; - String[] dicts = GameUtils.dictList( context ); + String[] dicts = DictUtils.dictList( context ); for ( String dict : dicts ) { if ( code == getDictLangCode( context, dict ) ) { ++count; @@ -107,7 +107,7 @@ public class DictLangCache { private static DictInfo[] getInfosHaveLang( Context context, int code ) { ArrayList al = new ArrayList(); - String[] dicts = GameUtils.dictList( context ); + String[] dicts = DictUtils.dictList( context ); for ( String dict : dicts ) { DictInfo info = getInfo( context, dict ); if ( code == info.langCode ) { @@ -200,7 +200,7 @@ public class DictLangCache { public static void inval( final Context context, String name, boolean added ) { - name = GameUtils.removeDictExtn( name ); + name = DictUtils.removeDictExtn( name ); s_nameToLang.remove( name ); if ( added ) { getInfo( context, name ); @@ -226,7 +226,7 @@ public class DictLangCache { 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 ) @@ -315,8 +315,8 @@ public class DictLangCache { if ( s_nameToLang.containsKey( name ) ) { info = s_nameToLang.get( name ); } else { - byte[] dict = GameUtils.openDict( context, name ); - String path = GameUtils.getDictPath( context, name ); + byte[] dict = DictUtils.openDict( context, name ); + String path = DictUtils.getDictPath( context, name ); info = new DictInfo(); XwJNI.dict_getInfo( dict, path, JNIUtilsImpl.get(), info ); info.name = name; diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictListPreference.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictListPreference.java index 072268dae..418798085 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictListPreference.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictListPreference.java @@ -32,7 +32,7 @@ public class DictListPreference extends XWListPreference { { super( context, attrs ); - String[] dicts = GameUtils.dictList( context ); + String[] dicts = DictUtils.dictList( context ); String[] dictEntries = new String[dicts.length]; for ( int ii = 0; ii < dicts.length; ++ii ) { dictEntries[ii] = diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java new file mode 100644 index 000000000..f8dd99050 --- /dev/null +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java @@ -0,0 +1,426 @@ +/* -*- 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 { + + public enum DictLoc { BUILT_IN, INTERNAL, EXTERNAL, DOWNLOAD }; + public static final String INVITED = "invited"; + + 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 String[] dictList( Context context ) + { + ArrayList al = new ArrayList(); + + 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 seen = new HashMap(); + 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 ) + { + 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; + } +} diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictsActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictsActivity.java index 7475222d1..a47ba3d69 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictsActivity.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictsActivity.java @@ -85,8 +85,8 @@ public class DictsActivity extends ExpandableListActivity private DictListAdapter m_adapter; private long m_packedPosition; - private GameUtils.DictLoc m_moveFromLoc; - private GameUtils.DictLoc m_moveToLoc; + private DictUtils.DictLoc m_moveFromLoc; + private DictUtils.DictLoc m_moveToLoc; private SDCardWatcher m_cardWatcher; private LayoutInflater m_factory; @@ -133,7 +133,7 @@ public class DictsActivity extends ExpandableListActivity boolean canDelete = false; if ( null != dicts && childPosition < dicts.length ) { text = dicts[childPosition]; - canDelete = !GameUtils.dictIsBuiltin( DictsActivity.this, + canDelete = !DictUtils.dictIsBuiltin( DictsActivity.this, text ); } else { text = m_download; @@ -144,8 +144,8 @@ public class DictsActivity extends ExpandableListActivity view.setDeleteCallback( DictsActivity.this ); } - GameUtils.DictLoc loc = - GameUtils.getDictLoc( DictsActivity.this, text ); + DictUtils.DictLoc loc = + DictUtils.getDictLoc( DictsActivity.this, text ); view.setComment( m_locNames[loc.ordinal()] ); view.cache( loc ); @@ -263,10 +263,10 @@ public class DictsActivity extends ExpandableListActivity lstnr = new DialogInterface.OnClickListener() { public void onClick( DialogInterface dlg, int item ) { XWListItem rowView = m_adapter.getSelChildView(); - if ( GameUtils.moveDict( DictsActivity.this, - rowView.getText(), - m_moveFromLoc, - m_moveToLoc ) ) { + if ( DictUtils.moveDict( DictsActivity.this, + rowView.getText(), + m_moveFromLoc, + m_moveToLoc ) ) { rowView. setComment( m_locNames[m_moveToLoc.ordinal()]); rowView.cache( m_moveToLoc ); @@ -408,11 +408,11 @@ public class DictsActivity extends ExpandableListActivity int tmp = savedInstanceState.getInt( MOVEFROMLOC, -1 ); if ( -1 != tmp ) { - m_moveFromLoc = GameUtils.DictLoc.values()[tmp]; + m_moveFromLoc = DictUtils.DictLoc.values()[tmp]; } tmp = savedInstanceState.getInt( MOVETOLOC, -1 ); 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 ); XWListItem row = (XWListItem)info.targetView; - GameUtils.DictLoc loc = (GameUtils.DictLoc)row.getCached(); - if ( loc == GameUtils.DictLoc.BUILT_IN - || ! GameUtils.haveWriteableSD() ) { + DictUtils.DictLoc loc = (DictUtils.DictLoc)row.getCached(); + if ( loc == DictUtils.DictLoc.BUILT_IN + || ! DictUtils.haveWriteableSD() ) { menu.removeItem( R.id.dicts_item_move ); } @@ -510,11 +510,11 @@ public class DictsActivity extends ExpandableListActivity // options for YY? private void askMoveDict( XWListItem item ) { - m_moveFromLoc = (GameUtils.DictLoc)item.getCached(); - if ( m_moveFromLoc == GameUtils.DictLoc.INTERNAL ) { - m_moveToLoc = GameUtils.DictLoc.EXTERNAL; + m_moveFromLoc = (DictUtils.DictLoc)item.getCached(); + if ( m_moveFromLoc == DictUtils.DictLoc.INTERNAL ) { + m_moveToLoc = DictUtils.DictLoc.EXTERNAL; } else { - m_moveToLoc = GameUtils.DictLoc.INTERNAL; + m_moveToLoc = DictUtils.DictLoc.INTERNAL; } showDialog( MOVE_DICT ); @@ -566,14 +566,14 @@ public class DictsActivity extends ExpandableListActivity private void deleteDict( String dict ) { - GameUtils.deleteDict( this, dict ); + DictUtils.deleteDict( this, dict ); DictLangCache.inval( this, dict, false ); mkListAdapter(); } private void askStartDownload( int lang, String name ) { - if ( GameUtils.haveWriteableSD() ) { + if ( DictUtils.haveWriteableSD() ) { m_lang = lang; m_name = name; showDialog( PICK_STORAGE ); 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 b3b79dd1f..abcc21946 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java @@ -47,7 +47,6 @@ import org.eehouse.android.xw4.jni.CurGameInfo.DeviceRole; public class GameUtils { - public enum DictLoc { BUILT_IN, INTERNAL, EXTERNAL, DOWNLOAD }; public static final String INVITED = "invited"; // 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(); public static byte[] savedGame( Context context, long rowid ) @@ -205,7 +180,7 @@ public class GameUtils { // as DeviceRole.SERVER_STANDALONE != gi.serverRole int gamePtr = loadMakeGame( context, gi, lockSrc ); String[] dictNames = gi.dictNames(); - DictPairs pairs = openDicts( context, dictNames ); + DictUtils.DictPairs pairs = DictUtils.openDicts( context, dictNames ); if ( XwJNI.game_hasComms( gamePtr ) ) { addr = new CommsAddrRec( context ); @@ -333,7 +308,7 @@ public class GameUtils { byte[] stream = savedGame( context, lock ); XwJNI.gi_from_stream( gi, stream ); String[] dictNames = gi.dictNames(); - DictPairs pairs = openDicts( context, dictNames ); + DictUtils.DictPairs pairs = DictUtils.openDicts( context, dictNames ); if ( pairs.anyMissing( dictNames ) ) { Utils.logf( "loadMakeGame() failing: dict unavailable" ); } else { @@ -490,7 +465,7 @@ public class GameUtils { { String[] dictNames = dictNames( context, rowid, missingLang ); HashSet missingSet; - String[] installed = dictList( context ); + String[] installed = DictUtils.dictList( context ); missingSet = new HashSet( Arrays.asList( dictNames ) ); missingSet.remove( null ); @@ -532,288 +507,11 @@ public class GameUtils { // return name; } - public static String[] dictList( Context context ) - { - ArrayList al = new ArrayList(); - - 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 seen = new HashMap(); - 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 ) { 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, boolean invited ) { @@ -925,7 +623,7 @@ public class GameUtils { gi.replaceDicts( newDict ); String[] dictNames = gi.dictNames(); - DictPairs pairs = openDicts( context, dictNames ); + DictUtils.DictPairs pairs = DictUtils.openDicts( context, dictNames ); int gamePtr = XwJNI.initJNI(); XwJNI.game_makeFromStream( gamePtr, stream, JNIUtilsImpl.get(), gi, @@ -950,7 +648,7 @@ public class GameUtils { // that don't reset the game, e.g. player name for standalone // games? String[] dictNames = gi.dictNames(); - DictPairs pairs = openDicts( context, dictNames ); + DictUtils.DictPairs pairs = DictUtils.openDicts( context, dictNames ); String langName = gi.langName(); int gamePtr = XwJNI.initJNI(); boolean madeGame = false; @@ -996,34 +694,6 @@ public class GameUtils { 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, boolean informNow ) { @@ -1036,43 +706,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; - } } diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CommonPrefs.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CommonPrefs.java index e5c972cef..6e2bcc22e 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CommonPrefs.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CommonPrefs.java @@ -29,7 +29,7 @@ import junit.framework.Assert; import org.eehouse.android.xw4.Utils; import org.eehouse.android.xw4.R; -import org.eehouse.android.xw4.GameUtils; +import org.eehouse.android.xw4.DictUtils; public class CommonPrefs { public static final int COLOR_TILE_BACK = 0; @@ -211,8 +211,8 @@ public class CommonPrefs { public static String getDefaultHumanDict( Context context ) { String value = getString( context, R.string.key_default_dict ); - if ( value.equals("") || !GameUtils.dictExists( context, value ) ) { - value = GameUtils.dictList( context )[0]; + if ( value.equals("") || !DictUtils.dictExists( context, value ) ) { + value = DictUtils.dictList( context )[0]; } return value; } @@ -220,7 +220,7 @@ public class CommonPrefs { public static String getDefaultRobotDict( Context context ) { 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 ); } return value; diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CurGameInfo.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CurGameInfo.java index 19f5f1e9b..b49dc41c9 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CurGameInfo.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CurGameInfo.java @@ -27,7 +27,7 @@ import java.util.Arrays; import junit.framework.Assert; 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.DictLangCache; @@ -403,7 +403,7 @@ public class CurGameInfo { DictLangCache.getBestDefault( m_context, dictLang, false ); if ( null == dictName - || ! GameUtils.dictExists( m_context, dictName ) + || ! DictUtils.dictExists( m_context, dictName ) || dictLang != DictLangCache.getDictLangCode( m_context, dictName ) ) { dictName = humanDict;