mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-29 08:34:37 +01:00
Add ability to open utf8-formatted dicts and to display bitmap tiles
(though poorly.) Both required processing in the jni that isn't possible (e.g. because no libiconv included) so I created callbacks into java from the dict building code. Add ability to download dicts, to select them, to add and remove players and make them robots or human. Robot-vs-robot game doesn't work well (robots trade a lot and server_do seems not to be getting called enough) but will soon. Coalesce penMove events. Implement game list menuitems like delete, copy, etc.
This commit is contained in:
parent
676fd73fc0
commit
68079d3590
21 changed files with 785 additions and 376 deletions
|
@ -29,7 +29,6 @@
|
|||
android:layout_marginRight="20dip"
|
||||
android:text="@string/players_label"
|
||||
android:gravity="left"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
/>
|
||||
|
||||
<Button android:id="@+id/add_player"
|
||||
|
@ -45,12 +44,27 @@
|
|||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="1"
|
||||
android:drawSelectorOnTop="false"/>
|
||||
android:drawSelectorOnTop="false"
|
||||
/>
|
||||
|
||||
<TextView android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_marginLeft="20dip"
|
||||
android:layout_marginRight="20dip"
|
||||
android:text="@string/dict_label"
|
||||
/>
|
||||
|
||||
<Spinner android:id="@+id/dict_spinner"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawSelectorOnTop="true"
|
||||
/>
|
||||
|
||||
<Button android:id="@+id/game_config_done"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="right"
|
||||
android:text="@string/game_config_done" />
|
||||
android:text="@string/button_save"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
|
|
@ -14,64 +14,70 @@
|
|||
limitations under the License.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/screen"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<CheckBox android:id="@+id/remote_check"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:text="@string/remote_label"
|
||||
/>
|
||||
|
||||
<CheckBox android:id="@+id/remote_check"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/remote_label"
|
||||
/>
|
||||
<TextView android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginLeft="20dip"
|
||||
android:layout_marginRight="20dip"
|
||||
android:text="@string/player_label"
|
||||
android:gravity="left"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
/>
|
||||
|
||||
<EditText android:id="@+id/player_name_edit"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_marginLeft="20dip"
|
||||
android:layout_marginRight="20dip"
|
||||
android:scrollHorizontally="true"
|
||||
android:autoText="false"
|
||||
android:capitalize="none"
|
||||
android:gravity="fill_horizontal"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
/>
|
||||
|
||||
<TextView android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginLeft="20dip"
|
||||
android:layout_marginRight="20dip"
|
||||
android:text="@string/player_label"
|
||||
android:gravity="left"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
/>
|
||||
|
||||
<EditText android:id="@+id/player_edit"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_marginLeft="20dip"
|
||||
android:layout_marginRight="20dip"
|
||||
android:scrollHorizontally="true"
|
||||
android:autoText="false"
|
||||
android:capitalize="none"
|
||||
android:gravity="fill_horizontal"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
/>
|
||||
<CheckBox android:id="@+id/robot_check"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/robot_label"
|
||||
/>
|
||||
|
||||
<CheckBox android:id="@+id/robot_check"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/robot_label"
|
||||
/>
|
||||
<TextView android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginLeft="20dip"
|
||||
android:layout_marginRight="20dip"
|
||||
android:text="@string/password_label"
|
||||
android:gravity="left"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
/>
|
||||
|
||||
<EditText android:id="@+id/password_edit"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_marginLeft="20dip"
|
||||
android:layout_marginRight="20dip"
|
||||
android:scrollHorizontally="true"
|
||||
android:autoText="false"
|
||||
android:capitalize="none"
|
||||
android:gravity="fill_horizontal"
|
||||
android:password="true"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
/>
|
||||
|
||||
<TextView android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginLeft="20dip"
|
||||
android:layout_marginRight="20dip"
|
||||
android:text="@string/password_label"
|
||||
android:gravity="left"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
/>
|
||||
|
||||
<EditText android:id="@+id/password_edit"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_marginLeft="20dip"
|
||||
android:layout_marginRight="20dip"
|
||||
android:scrollHorizontally="true"
|
||||
android:autoText="false"
|
||||
android:capitalize="none"
|
||||
android:gravity="fill_horizontal"
|
||||
android:password="true"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
|
|
@ -13,22 +13,22 @@
|
|||
<item android:id="@+id/list_item_new_from"
|
||||
android:title="@string/list_item_new_from"
|
||||
/>
|
||||
<item android:id="@+id/list_item_hide"
|
||||
android:title="@string/list_item_hide"
|
||||
/>
|
||||
<!-- <item android:id="@+id/list_item_hide" -->
|
||||
<!-- android:title="@string/list_item_hide" -->
|
||||
<!-- /> -->
|
||||
<item android:id="@+id/list_item_delete"
|
||||
android:title="@string/list_item_delete"
|
||||
/>
|
||||
<item android:id="@+id/list_item_move_up"
|
||||
android:title="@string/list_item_move_up"
|
||||
/>
|
||||
<item android:id="@+id/list_item_move_down"
|
||||
android:title="@string/list_item_move_down"
|
||||
/>
|
||||
<item android:id="@+id/list_item_move_to_top"
|
||||
android:title="@string/list_item_move_to_top"
|
||||
/>
|
||||
<item android:id="@+id/list_item_move_to_bottom"
|
||||
android:title="@string/list_item_move_to_bottom"
|
||||
/>
|
||||
<!-- <item android:id="@+id/list_item_move_up" -->
|
||||
<!-- android:title="@string/list_item_move_up" -->
|
||||
<!-- /> -->
|
||||
<!-- <item android:id="@+id/list_item_move_down" -->
|
||||
<!-- android:title="@string/list_item_move_down" -->
|
||||
<!-- /> -->
|
||||
<!-- <item android:id="@+id/list_item_move_to_top" -->
|
||||
<!-- android:title="@string/list_item_move_to_top" -->
|
||||
<!-- /> -->
|
||||
<!-- <item android:id="@+id/list_item_move_to_bottom" -->
|
||||
<!-- android:title="@string/list_item_move_to_bottom" -->
|
||||
<!-- /> -->
|
||||
</menu>
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
<string name="menu_discard">Discard</string>
|
||||
|
||||
<string name="list_item_open">Open</string>
|
||||
<string name="list_item_view">View me</string>
|
||||
<string name="list_item_view">Configure</string>
|
||||
<string name="list_item_hide">Hide</string>
|
||||
<string name="list_item_delete">Delete</string>
|
||||
<string name="list_item_copy">Copy</string>
|
||||
|
@ -49,6 +49,7 @@
|
|||
<string name="button_cancel">Cancel</string>
|
||||
<string name="button_yes">Yes</string>
|
||||
<string name="button_no">No</string>
|
||||
<string name="button_save">Save</string>
|
||||
|
||||
<string name="player_label">Name:</string>
|
||||
<string name="game_config_open">Open</string>
|
||||
|
@ -115,11 +116,11 @@
|
|||
<string name="strsd_summaryscored"></string>
|
||||
<string name="strd_traded">%s:%d</string>
|
||||
<string name="str_lostturn">Lost turn</string>
|
||||
<string name="str_commit_confirm">Commit the current move?</string>
|
||||
<string name="str_commit_confirm">Commit the current move?\n</string>
|
||||
<string name="str_local_name">%s</string>
|
||||
<string name="str_nonlocal_name">%s (remote)</string>
|
||||
<string name="str_bonus_all">Bonus for using all tiles: 50</string>
|
||||
<string name="strd_turn_score">Score for turn: %d</string>
|
||||
<string name="str_bonus_all">Bonus for using all tiles: 50\n</string>
|
||||
<string name="strd_turn_score">Score for turn: %d\n</string>
|
||||
|
||||
<!-- error messages -->
|
||||
<string name="str_tiles_not_in_line">All tiles played must be in a line.</string>
|
||||
|
@ -150,4 +151,9 @@
|
|||
<string name="list_item_up">Up one</string>
|
||||
<string name="list_item_down">Down one</string>
|
||||
|
||||
<string name="dict_label">Dictionary</string>
|
||||
<string name="download_dicts">Download more...</string>
|
||||
|
||||
<string name="dict_url">http://eehouse.org/and_dicts</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -8,6 +8,7 @@ import android.content.Intent;
|
|||
import android.app.Dialog;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.res.Configuration;
|
||||
|
||||
public class BlockingActivity extends Activity {
|
||||
|
||||
|
@ -32,37 +33,41 @@ public class BlockingActivity extends Activity {
|
|||
.setCancelable( false );
|
||||
|
||||
if ( 0 != m_butPos ) {
|
||||
ab.setPositiveButton( m_butPos,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick( DialogInterface dialog,
|
||||
int whichButton ) {
|
||||
Utils.logf( "Yes clicked" );
|
||||
setResult( 1 );
|
||||
finish();
|
||||
}
|
||||
});
|
||||
DialogInterface.OnClickListener lstnr
|
||||
= new DialogInterface.OnClickListener() {
|
||||
public void onClick( DialogInterface dialog,
|
||||
int whichButton ) {
|
||||
Utils.logf( "Yes clicked" );
|
||||
setResult( 1 );
|
||||
finish();
|
||||
}
|
||||
};
|
||||
ab.setPositiveButton( m_butPos, lstnr );
|
||||
}
|
||||
|
||||
if ( 0 != m_butNeg ) {
|
||||
ab.setNegativeButton( m_butNeg,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick( DialogInterface dialog,
|
||||
int whichButton ) {
|
||||
Utils.logf( "No clicked" );
|
||||
setResult( 0 );
|
||||
finish();
|
||||
}
|
||||
});
|
||||
DialogInterface.OnClickListener lstnr =
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick( DialogInterface dialog,
|
||||
int whichButton ) {
|
||||
Utils.logf( "No clicked" );
|
||||
setResult( 0 );
|
||||
finish();
|
||||
}
|
||||
};
|
||||
ab.setNegativeButton( m_butNeg, lstnr );
|
||||
}
|
||||
|
||||
if ( null != m_tiles ) {
|
||||
Utils.logf( "adding m_tiles; len=" + m_tiles.length );
|
||||
ab.setItems( m_tiles, new DialogInterface.OnClickListener() {
|
||||
public void onClick( DialogInterface dialog, int item ) {
|
||||
DialogInterface.OnClickListener lstnr =
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick( DialogInterface dialog,
|
||||
int item ) {
|
||||
setResult( RESULT_FIRST_USER + item );
|
||||
finish();
|
||||
}
|
||||
});
|
||||
};
|
||||
ab.setItems( m_tiles, lstnr );
|
||||
} else if ( null != m_query ) {
|
||||
ab.setMessage( m_query );
|
||||
}
|
||||
|
|
|
@ -9,10 +9,12 @@ import android.view.MenuItem;
|
|||
import android.view.MenuInflater;
|
||||
import android.content.res.AssetManager;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.Intent;
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
@ -20,6 +22,10 @@ import android.net.Uri;
|
|||
import android.app.Dialog;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.Bitmap;
|
||||
import java.util.ArrayList;
|
||||
import android.content.res.Resources;
|
||||
|
||||
import org.eehouse.android.xw4.jni.*;
|
||||
import org.eehouse.android.xw4.jni.JNIThread.*;
|
||||
|
@ -100,7 +106,8 @@ public class BoardActivity extends Activity implements XW_UtilCtxt, Runnable {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate( Bundle savedInstanceState ) {
|
||||
protected void onCreate( Bundle savedInstanceState )
|
||||
{
|
||||
super.onCreate( savedInstanceState );
|
||||
|
||||
setContentView( R.layout.board );
|
||||
|
@ -122,60 +129,44 @@ public class BoardActivity extends Activity implements XW_UtilCtxt, Runnable {
|
|||
byte[] stream = Utils.savedGame( this, m_path );
|
||||
XwJNI.gi_from_stream( m_gi, stream );
|
||||
|
||||
byte[] dictBytes = null;
|
||||
InputStream dict = null;
|
||||
AssetManager am = getAssets();
|
||||
try {
|
||||
dict = am.open( m_gi.dictName,
|
||||
android.content.res.AssetManager.ACCESS_RANDOM );
|
||||
Utils.logf( "opened dict" );
|
||||
Utils.logf( "dict name: " + m_gi.dictName );
|
||||
byte[] dictBytes = Utils.openDict( this, m_gi.dictName );
|
||||
if ( null == dictBytes ) {
|
||||
Utils.logf( "**** unable to open dict; warn user! ****" );
|
||||
finish();
|
||||
} else {
|
||||
m_jniGamePtr = XwJNI.initJNI();
|
||||
|
||||
int len = dict.available();
|
||||
Utils.logf( "dict size: " + len );
|
||||
dictBytes = new byte[len];
|
||||
int nRead = dict.read( dictBytes, 0, len );
|
||||
if ( nRead != len ) {
|
||||
Utils.logf( "**** warning ****; read only " + nRead + " of "
|
||||
+ len + " bytes." );
|
||||
if ( null == stream ||
|
||||
! XwJNI.game_makeFromStream( m_jniGamePtr, stream,
|
||||
m_gi, dictBytes, this,
|
||||
m_view, m_prefs,
|
||||
null ) ) {
|
||||
XwJNI.game_makeNewGame( m_jniGamePtr, m_gi, this, m_view, 0,
|
||||
m_prefs, null, dictBytes );
|
||||
}
|
||||
} catch ( java.io.IOException ee ){
|
||||
Utils.logf( "failed to open" );
|
||||
}
|
||||
|
||||
m_jniGamePtr = XwJNI.initJNI();
|
||||
|
||||
if ( null == stream ||
|
||||
! XwJNI.game_makeFromStream( m_jniGamePtr, stream,
|
||||
m_gi, dictBytes, this,
|
||||
m_view, m_prefs,
|
||||
null ) ) {
|
||||
XwJNI.game_makeNewGame( m_jniGamePtr, m_gi, this, m_view, 0,
|
||||
m_prefs, null, dictBytes );
|
||||
}
|
||||
|
||||
m_jniThread = new
|
||||
JNIThread( m_jniGamePtr,
|
||||
new Handler() {
|
||||
public void handleMessage( Message msg ) {
|
||||
Utils.logf( "handleMessage() called" );
|
||||
switch( msg.what ) {
|
||||
case JNIThread.DRAW:
|
||||
m_view.invalidate();
|
||||
break;
|
||||
case JNIThread.DIALOG:
|
||||
m_dlgBytes = (String)msg.obj;
|
||||
m_dlgTitle = msg.arg1;
|
||||
showDialog( DLG_OKONLY );
|
||||
break;
|
||||
m_jniThread = new
|
||||
JNIThread( m_jniGamePtr,
|
||||
new Handler() {
|
||||
public void handleMessage( Message msg ) {
|
||||
switch( msg.what ) {
|
||||
case JNIThread.DRAW:
|
||||
m_view.invalidate();
|
||||
break;
|
||||
case JNIThread.DIALOG:
|
||||
m_dlgBytes = (String)msg.obj;
|
||||
m_dlgTitle = msg.arg1;
|
||||
showDialog( DLG_OKONLY );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} );
|
||||
m_jniThread.start();
|
||||
} );
|
||||
m_jniThread.start();
|
||||
|
||||
m_view.startHandling( m_jniThread, m_jniGamePtr, m_gi );
|
||||
m_jniThread.handle( JNICmd.CMD_DO );
|
||||
|
||||
Utils.logf( "BoardActivity::onCreate() done" );
|
||||
m_view.startHandling( m_jniThread, m_jniGamePtr, m_gi );
|
||||
m_jniThread.handle( JNICmd.CMD_DO );
|
||||
}
|
||||
} // onCreate
|
||||
|
||||
// protected void onPause() {
|
||||
|
@ -186,19 +177,21 @@ public class BoardActivity extends Activity implements XW_UtilCtxt, Runnable {
|
|||
|
||||
protected void onDestroy()
|
||||
{
|
||||
// what if m_jniThread is null?
|
||||
m_jniThread.waitToStop();
|
||||
if ( null != m_jniThread ) {
|
||||
m_jniThread.waitToStop();
|
||||
Utils.logf( "onDestroy(): waitToStop() returned" );
|
||||
|
||||
byte[] state = XwJNI.game_saveToStream( m_jniGamePtr, m_gi );
|
||||
Utils.saveGame( this, state, m_path );
|
||||
byte[] state = XwJNI.game_saveToStream( m_jniGamePtr, m_gi );
|
||||
Utils.saveGame( this, state, m_path );
|
||||
|
||||
XwJNI.game_dispose( m_jniGamePtr );
|
||||
m_jniGamePtr = 0;
|
||||
XwJNI.game_dispose( m_jniGamePtr );
|
||||
m_jniGamePtr = 0;
|
||||
}
|
||||
|
||||
super.onDestroy();
|
||||
Utils.logf( "onDestroy done" );
|
||||
}
|
||||
|
||||
|
||||
protected void onActivityResult( int requestCode, int resultCode,
|
||||
Intent result )
|
||||
{
|
||||
|
@ -287,11 +280,12 @@ public class BoardActivity extends Activity implements XW_UtilCtxt, Runnable {
|
|||
|
||||
// gets called for orientation changes only if
|
||||
// android:configChanges="orientation" set in AndroidManifest.xml
|
||||
|
||||
// public void onConfigurationChanged( Configuration newConfig )
|
||||
// {
|
||||
// super.onConfigurationChanged( newConfig );
|
||||
// }
|
||||
public void onConfigurationChanged( Configuration newConfig )
|
||||
{
|
||||
Utils.logf( "BoardActivity::onConfigurationChanged called" );
|
||||
m_view.changeLayout();
|
||||
super.onConfigurationChanged( newConfig );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
// XW_UtilCtxt interface implementation //
|
||||
|
@ -569,4 +563,62 @@ public class BoardActivity extends Activity implements XW_UtilCtxt, Runnable {
|
|||
R.string.finalscores_title );
|
||||
}
|
||||
|
||||
public BitmapDrawable makeBitmap( int width, int height, boolean[] colors )
|
||||
{
|
||||
Bitmap bitmap = Bitmap.createBitmap( width, height,
|
||||
Bitmap.Config.ARGB_8888 );
|
||||
|
||||
int indx = 0;
|
||||
for ( int yy = 0; yy < height; ++yy ) {
|
||||
for ( int xx = 0; xx < width; ++xx ) {
|
||||
boolean pixelSet = colors[indx++];
|
||||
bitmap.setPixel( xx, yy, pixelSet? 0xFF000000 : 0x00FFFFFF );
|
||||
}
|
||||
}
|
||||
|
||||
// Doesn't compile if pass getResources(). Maybe the
|
||||
// "deprecated" API is really the only one?
|
||||
return new BitmapDrawable( /*getResources(), */bitmap );
|
||||
}
|
||||
|
||||
/** Working around lack of utf8 support on the JNI side: given a
|
||||
* utf-8 string with embedded small number vals starting with 0,
|
||||
* convert into individual strings. The 0 is the problem: it's
|
||||
* not valid utf8. So turn it and the other nums into strings and
|
||||
* catch them on the other side.
|
||||
*/
|
||||
public String[] splitFaces( byte[] chars )
|
||||
{
|
||||
ArrayList<String> al = new ArrayList<String>();
|
||||
int ii = 0;
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream( chars );
|
||||
InputStreamReader isr = new InputStreamReader( bais );
|
||||
|
||||
int[] codePoints = new int[1];
|
||||
|
||||
for ( ; ; ) {
|
||||
int chr = -1;
|
||||
try {
|
||||
chr = isr.read();
|
||||
} catch ( java.io.IOException ioe ) {
|
||||
Utils.logf( ioe.toString() );
|
||||
}
|
||||
if ( -1 == chr ) {
|
||||
break;
|
||||
} else {
|
||||
String letter;
|
||||
if ( chr < 32 ) {
|
||||
letter = String.format( "%d", chr );
|
||||
} else {
|
||||
codePoints[0] = chr;
|
||||
letter = new String( codePoints, 0, 1 );
|
||||
}
|
||||
al.add( letter );
|
||||
}
|
||||
}
|
||||
|
||||
String[] result = al.toArray( new String[al.size()] );
|
||||
return result;
|
||||
}
|
||||
|
||||
} // class BoardActivity
|
||||
|
|
|
@ -12,6 +12,7 @@ import android.util.AttributeSet;
|
|||
import org.eehouse.android.xw4.jni.*;
|
||||
import android.view.MotionEvent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.content.res.Resources;
|
||||
|
||||
public class BoardView extends View implements DrawCtx,
|
||||
|
@ -163,23 +164,6 @@ public class BoardView extends View implements DrawCtx,
|
|||
m_top = 0;
|
||||
}
|
||||
|
||||
// XwJNI.board_setScoreboardLoc( m_jniGamePtr, 0, 0,
|
||||
// nCells * cellSize, // width
|
||||
// scoreHt, true );
|
||||
|
||||
// XwJNI.board_setPos( m_jniGamePtr, 0, scoreHt, false );
|
||||
// XwJNI.board_setScale( m_jniGamePtr, cellSize, cellSize );
|
||||
|
||||
// XwJNI.board_setTrayLoc( m_jniGamePtr, 0,
|
||||
// scoreHt + ((nCells-nToScroll) * cellSize),
|
||||
// nCells * cellSize, // width
|
||||
// trayHt, // height
|
||||
// 4 );
|
||||
|
||||
// XwJNI.board_setShowColors( m_jniGamePtr, true ); // get from prefs!
|
||||
|
||||
// XwJNI.board_invalAll( m_jniGamePtr );
|
||||
|
||||
m_bitmap = Bitmap.createBitmap( 1 + (cellSize*nCells),
|
||||
1 + trayHt + scoreHt
|
||||
+ (cellSize *(nCells-nToScroll)),
|
||||
|
@ -194,6 +178,11 @@ public class BoardView extends View implements DrawCtx,
|
|||
return m_boardSet;
|
||||
}
|
||||
|
||||
public void changeLayout()
|
||||
{
|
||||
m_boardSet = false;
|
||||
}
|
||||
|
||||
public void startHandling( JNIThread thread, int gamePtr, CurGameInfo gi )
|
||||
{
|
||||
m_jniThread = thread;
|
||||
|
@ -269,7 +258,7 @@ public class BoardView extends View implements DrawCtx,
|
|||
drawCentered( text, rOuter );
|
||||
}
|
||||
|
||||
public boolean drawCell( Rect rect, String text, Object[] bitmaps,
|
||||
public boolean drawCell( Rect rect, String text, BitmapDrawable[] bitmaps,
|
||||
int tile, int owner, int bonus, int hintAtts,
|
||||
int flags )
|
||||
{
|
||||
|
@ -298,12 +287,14 @@ public class BoardView extends View implements DrawCtx,
|
|||
m_origin.draw( m_canvas );
|
||||
}
|
||||
} else {
|
||||
m_fillPaint.setTextSize( rect.bottom - rect.top );
|
||||
if ( owner < 0 ) { // showColors option not turned on
|
||||
owner = 0;
|
||||
}
|
||||
m_fillPaint.setColor( foreColor );
|
||||
drawCentered( text, rect );
|
||||
if ( null == bitmaps ) {
|
||||
m_fillPaint.setTextSize( rect.bottom - rect.top );
|
||||
drawCentered( text, rect );
|
||||
} else {
|
||||
bitmaps[0].setBounds( rect );
|
||||
bitmaps[0].draw( m_canvas );
|
||||
}
|
||||
}
|
||||
|
||||
m_canvas.drawRect( rect, m_strokePaint );
|
||||
|
@ -331,43 +322,21 @@ public class BoardView extends View implements DrawCtx,
|
|||
return true;
|
||||
}
|
||||
|
||||
public void drawTile( Rect rect, String text, Object[] bitmaps, int val,
|
||||
public void drawTile( Rect rect, String text, BitmapDrawable[] bitmaps, int val,
|
||||
int flags )
|
||||
{
|
||||
boolean valHidden = (flags & CELL_VALHIDDEN) != 0;
|
||||
boolean notEmpty = (flags & CELL_ISEMPTY) == 0;
|
||||
boolean isCursor = (flags & CELL_ISCURSOR) != 0;
|
||||
|
||||
m_canvas.save( Canvas.CLIP_SAVE_FLAG );
|
||||
m_canvas.clipRect( rect );
|
||||
|
||||
clearToBack( rect );
|
||||
|
||||
if ( isCursor || notEmpty ) {
|
||||
m_fillPaint.setColor( TILE_BACK );
|
||||
m_canvas.drawRect( rect, m_fillPaint );
|
||||
|
||||
m_fillPaint.setColor( m_playerColors[m_trayOwner] );
|
||||
positionDrawTile( rect, text, val );
|
||||
|
||||
m_canvas.drawRect( rect, m_tileStrokePaint); // frame
|
||||
if ( 0 != (flags & CELL_HIGHLIGHT) ) {
|
||||
rect.inset( 2, 2 );
|
||||
m_canvas.drawRect( rect, m_tileStrokePaint ); // frame
|
||||
}
|
||||
}
|
||||
m_canvas.restore();
|
||||
drawTileImpl( rect, text, bitmaps, val, flags, true );
|
||||
}
|
||||
|
||||
public void drawTileMidDrag ( Rect rect, String text, Object[] bitmaps,
|
||||
public void drawTileMidDrag( Rect rect, String text, BitmapDrawable[] bitmaps,
|
||||
int val, int owner, int flags )
|
||||
{
|
||||
drawTile( rect, text, bitmaps, val, flags );
|
||||
drawTileImpl( rect, text, bitmaps, val, flags, false );
|
||||
}
|
||||
|
||||
public void drawTileBack( Rect rect, int flags )
|
||||
{
|
||||
drawTile( rect, "?", null, -1, flags );
|
||||
drawTileImpl( rect, "?", null, -1, flags, true );
|
||||
}
|
||||
|
||||
public void drawTrayDivider( Rect rect, int flags )
|
||||
|
@ -394,6 +363,40 @@ public class BoardView extends View implements DrawCtx,
|
|||
}
|
||||
}
|
||||
|
||||
private void drawTileImpl( Rect rect, String text,
|
||||
BitmapDrawable[] bitmaps, int val,
|
||||
int flags, boolean clearBack )
|
||||
{
|
||||
boolean valHidden = (flags & CELL_VALHIDDEN) != 0;
|
||||
boolean notEmpty = (flags & CELL_ISEMPTY) == 0;
|
||||
boolean isCursor = (flags & CELL_ISCURSOR) != 0;
|
||||
|
||||
m_canvas.save( Canvas.CLIP_SAVE_FLAG );
|
||||
m_canvas.clipRect( rect );
|
||||
|
||||
if ( clearBack ) {
|
||||
clearToBack( rect );
|
||||
}
|
||||
|
||||
if ( isCursor || notEmpty ) {
|
||||
|
||||
if ( clearBack ) {
|
||||
m_fillPaint.setColor( TILE_BACK );
|
||||
m_canvas.drawRect( rect, m_fillPaint );
|
||||
}
|
||||
|
||||
m_fillPaint.setColor( m_playerColors[m_trayOwner] );
|
||||
positionDrawTile( rect, text, bitmaps, val );
|
||||
|
||||
m_canvas.drawRect( rect, m_tileStrokePaint); // frame
|
||||
if ( 0 != (flags & CELL_HIGHLIGHT) ) {
|
||||
rect.inset( 2, 2 );
|
||||
m_canvas.drawRect( rect, m_tileStrokePaint ); // frame
|
||||
}
|
||||
}
|
||||
m_canvas.restore();
|
||||
}
|
||||
|
||||
private void drawCentered( String text, Rect rect )
|
||||
{
|
||||
int bottom = rect.bottom;
|
||||
|
@ -401,17 +404,23 @@ public class BoardView extends View implements DrawCtx,
|
|||
m_canvas.drawText( text, center, bottom, m_fillPaint );
|
||||
}
|
||||
|
||||
private void positionDrawTile( Rect rect, String text, int val )
|
||||
private void positionDrawTile( Rect rect, String text,
|
||||
BitmapDrawable bitmaps[], int val )
|
||||
{
|
||||
if ( null != text ) {
|
||||
|
||||
if ( null != bitmaps || null != text ) {
|
||||
if ( null == m_letterRect ) {
|
||||
// assumes show values is on
|
||||
m_letterRect = new Rect( 0, 0, rect.width() * 3 / 4,
|
||||
rect.height() * 3 / 4 );
|
||||
}
|
||||
m_letterRect.offsetTo( rect.left, rect.top );
|
||||
m_fillPaint.setTextSize( m_letterRect.height() );
|
||||
drawCentered( text, m_letterRect );
|
||||
if ( null != bitmaps ) {
|
||||
bitmaps[0].setBounds( m_letterRect );
|
||||
bitmaps[0].draw( m_canvas );
|
||||
} else /*if ( null != text )*/ {
|
||||
m_fillPaint.setTextSize( m_letterRect.height() );
|
||||
drawCentered( text, m_letterRect );
|
||||
}
|
||||
}
|
||||
|
||||
if ( val >= 0 ) {
|
||||
|
|
|
@ -36,6 +36,7 @@ import android.view.Menu;
|
|||
import android.view.MenuItem;
|
||||
import android.widget.EditText;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemSelectedListener;
|
||||
import android.widget.ListView;
|
||||
import android.widget.ListAdapter;
|
||||
import android.view.View;
|
||||
|
@ -57,6 +58,10 @@ import android.view.ContextMenu.ContextMenuInfo;
|
|||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MenuInflater;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.webkit.WebView;
|
||||
import java.io.File;
|
||||
|
||||
import org.eehouse.android.xw4.jni.*;
|
||||
|
||||
|
@ -76,6 +81,9 @@ public class GameConfig extends ListActivity implements View.OnClickListener {
|
|||
private CurGameInfo m_gi;
|
||||
private int m_whichPlayer;
|
||||
private Dialog m_curDialog;
|
||||
private Spinner m_dictSpinner;
|
||||
private String[] m_dicts;
|
||||
private int m_browsePosition;
|
||||
|
||||
private class PlayerListAdapter implements ListAdapter {
|
||||
public boolean areAllItemsEnabled() {
|
||||
|
@ -140,24 +148,20 @@ public class GameConfig extends ListActivity implements View.OnClickListener {
|
|||
final View playerEditView
|
||||
= factory.inflate( R.layout.player_edit, null );
|
||||
|
||||
DialogInterface.OnClickListener dlpos =
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick( DialogInterface dialog,
|
||||
int whichButton ) {
|
||||
getPlayerSettings();
|
||||
onContentChanged();
|
||||
}
|
||||
};
|
||||
|
||||
return new AlertDialog.Builder( this )
|
||||
// .setIcon(R.drawable.alert_dialog_icon)
|
||||
.setTitle(R.string.player_edit_title)
|
||||
.setView(playerEditView)
|
||||
.setPositiveButton(R.string.button_ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick( DialogInterface dialog,
|
||||
int whichButton ) {
|
||||
getPlayerSettings();
|
||||
onContentChanged();
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.button_cancel,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog,
|
||||
int whichButton) {
|
||||
}
|
||||
})
|
||||
.setPositiveButton(R.string.button_save, dlpos )
|
||||
.create();
|
||||
}
|
||||
return null;
|
||||
|
@ -174,36 +178,30 @@ public class GameConfig extends ListActivity implements View.OnClickListener {
|
|||
private void setPlayerSettings()
|
||||
{
|
||||
LocalPlayer lp = m_gi.players[m_whichPlayer];
|
||||
EditText player = (EditText)m_curDialog.findViewById( R.id.player_edit );
|
||||
EditText player = (EditText)
|
||||
m_curDialog.findViewById( R.id.player_name_edit );
|
||||
player.setText( lp.name );
|
||||
CheckBox isRobot = (CheckBox)m_curDialog.findViewById( R.id.robot_check );
|
||||
CheckBox isRobot = (CheckBox)
|
||||
m_curDialog.findViewById( R.id.robot_check );
|
||||
isRobot.setChecked( lp.isRobot );
|
||||
}
|
||||
|
||||
private void getPlayerSettings()
|
||||
{
|
||||
LocalPlayer lp = m_gi.players[m_whichPlayer];
|
||||
EditText player = (EditText)m_curDialog.findViewById( R.id.player_edit );
|
||||
EditText player = (EditText)
|
||||
m_curDialog.findViewById( R.id.player_name_edit );
|
||||
lp.name = player.getText().toString();
|
||||
CheckBox isRobot = (CheckBox)m_curDialog.findViewById( R.id.robot_check );
|
||||
CheckBox isRobot = (CheckBox)
|
||||
m_curDialog.findViewById( R.id.robot_check );
|
||||
lp.isRobot = isRobot.isChecked();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate( Bundle savedInstanceState )
|
||||
public void onCreate( Bundle savedInstanceState )
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.game_config);
|
||||
registerForContextMenu( getListView() );
|
||||
|
||||
mDoneB = (Button)findViewById(R.id.game_config_done);
|
||||
mDoneB.setOnClickListener( this );
|
||||
|
||||
m_addPlayerButton = (Button)findViewById(R.id.add_player);
|
||||
m_addPlayerButton.setOnClickListener( this );
|
||||
|
||||
// Do some setup based on the action being performed.
|
||||
Intent intent = getIntent();
|
||||
Uri uri = intent.getData();
|
||||
m_path = uri.getPath();
|
||||
|
@ -214,6 +212,47 @@ public class GameConfig extends ListActivity implements View.OnClickListener {
|
|||
byte[] stream = Utils.savedGame( this, m_path );
|
||||
m_gi = new CurGameInfo();
|
||||
XwJNI.gi_from_stream( m_gi, stream );
|
||||
int curSel = listAvailableDicts( m_gi.dictName );
|
||||
Utils.logf( "listAvailableDicts done" );
|
||||
|
||||
setContentView(R.layout.game_config);
|
||||
registerForContextMenu( getListView() );
|
||||
|
||||
mDoneB = (Button)findViewById(R.id.game_config_done);
|
||||
mDoneB.setOnClickListener( this );
|
||||
|
||||
m_addPlayerButton = (Button)findViewById(R.id.add_player);
|
||||
m_addPlayerButton.setOnClickListener( this );
|
||||
|
||||
m_dictSpinner = (Spinner)findViewById( R.id.dict_spinner );
|
||||
ArrayAdapter<String> adapter =
|
||||
new ArrayAdapter<String>( this,
|
||||
android.R.layout.simple_spinner_item,
|
||||
m_dicts );
|
||||
int resID = android.R.layout.simple_spinner_dropdown_item;
|
||||
adapter.setDropDownViewResource( resID );
|
||||
m_dictSpinner.setAdapter( adapter );
|
||||
if ( curSel >= 0 ) {
|
||||
m_dictSpinner.setSelection( curSel );
|
||||
}
|
||||
|
||||
m_dictSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parentView,
|
||||
View selectedItemView, int position,
|
||||
long id) {
|
||||
if ( position == m_browsePosition ) {
|
||||
launchDictBrowser();
|
||||
} else {
|
||||
m_gi.dictName = m_dicts[position];
|
||||
Utils.logf( "assigned dictName: " + m_gi.dictName );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parentView) {
|
||||
}
|
||||
});
|
||||
|
||||
setListAdapter( new PlayerListAdapter() );
|
||||
} // onCreate
|
||||
|
@ -316,4 +355,32 @@ public class GameConfig extends ListActivity implements View.OnClickListener {
|
|||
}
|
||||
} // onClick
|
||||
|
||||
|
||||
private int listAvailableDicts( String curDict )
|
||||
{
|
||||
int curSel = -1;
|
||||
|
||||
String[] list = Utils.listDicts( this );
|
||||
|
||||
m_browsePosition = list.length;
|
||||
m_dicts = new String[m_browsePosition+1];
|
||||
m_dicts[m_browsePosition] = getString( R.string.download_dicts );
|
||||
|
||||
for ( int ii = 0; ii < m_browsePosition; ++ii ) {
|
||||
String dict = list[ii];
|
||||
m_dicts[ii] = dict;
|
||||
if ( dict.equals( curDict ) ) {
|
||||
curSel = ii;
|
||||
}
|
||||
}
|
||||
|
||||
return curSel;
|
||||
}
|
||||
|
||||
private void launchDictBrowser()
|
||||
{
|
||||
Intent intent = new Intent( this, DictActivity.class );
|
||||
intent.setAction( Intent.ACTION_EDIT );
|
||||
startActivity( intent );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,7 +91,8 @@ public class GamesList extends ListActivity implements View.OnClickListener {
|
|||
@Override
|
||||
public boolean onContextItemSelected( MenuItem item )
|
||||
{
|
||||
boolean handled = false;
|
||||
boolean handled = true;
|
||||
byte[] stream;
|
||||
|
||||
AdapterView.AdapterContextMenuInfo info;
|
||||
try {
|
||||
|
@ -100,6 +101,8 @@ public class GamesList extends ListActivity implements View.OnClickListener {
|
|||
Utils.logf( "bad menuInfo:" + e.toString() );
|
||||
return false;
|
||||
}
|
||||
|
||||
String path = fileList()[info.position];
|
||||
|
||||
switch (item.getItemId()) {
|
||||
// case R.id.list_item_open:
|
||||
|
@ -107,24 +110,47 @@ public class GamesList extends ListActivity implements View.OnClickListener {
|
|||
// handled = true;
|
||||
// break;
|
||||
case R.id.list_item_view:
|
||||
doView( info.position );
|
||||
handled = true;
|
||||
doView( path );
|
||||
break;
|
||||
case R.id.list_item_delete:
|
||||
if ( ! deleteFile( path ) ) {
|
||||
Utils.logf( "unable to delete " + path );
|
||||
}
|
||||
break;
|
||||
|
||||
case R.id.list_item_hide:
|
||||
case R.id.list_item_delete:
|
||||
case R.id.list_item_copy:
|
||||
stream = Utils.savedGame( this, path );
|
||||
Utils.saveGame( this, stream );
|
||||
break;
|
||||
|
||||
case R.id.list_item_new_from:
|
||||
case R.id.list_item_move_up:
|
||||
case R.id.list_item_move_down:
|
||||
case R.id.list_item_move_to_top:
|
||||
case R.id.list_item_move_to_bottom:
|
||||
handled = true;
|
||||
Utils.notImpl( this );
|
||||
stream = Utils.savedGame( this, path );
|
||||
CurGameInfo gi = new CurGameInfo();
|
||||
XwJNI.gi_from_stream( gi, stream );
|
||||
stream = XwJNI.gi_to_stream( gi );
|
||||
Utils.saveGame( this, stream );
|
||||
break;
|
||||
|
||||
// These require some notion of predictable sort order.
|
||||
// Maybe put off until I'm using a db?
|
||||
// case R.id.list_item_hide:
|
||||
// case R.id.list_item_move_up:
|
||||
// case R.id.list_item_move_down:
|
||||
// case R.id.list_item_move_to_top:
|
||||
// case R.id.list_item_move_to_bottom:
|
||||
// Utils.notImpl( this );
|
||||
// break;
|
||||
default:
|
||||
handled = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( handled ) {
|
||||
onContentChanged();
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
} // onContextItemSelected
|
||||
|
||||
public boolean onCreateOptionsMenu( Menu menu )
|
||||
{
|
||||
|
@ -139,8 +165,13 @@ public class GamesList extends ListActivity implements View.OnClickListener {
|
|||
|
||||
switch (item.getItemId()) {
|
||||
case R.id.gamel_menu_delete_all:
|
||||
for( String file : fileList() ) {
|
||||
deleteFile( file );
|
||||
String[] files = fileList();
|
||||
for( String file : files ) {
|
||||
if ( deleteFile( file ) ) {
|
||||
Utils.logf( "deleted " + file );
|
||||
} else {
|
||||
Utils.logf( "unable to delete " + file );
|
||||
}
|
||||
}
|
||||
m_adapter = new GameListAdapter( this );
|
||||
setListAdapter( m_adapter );
|
||||
|
@ -172,42 +203,20 @@ public class GamesList extends ListActivity implements View.OnClickListener {
|
|||
startActivity( intent );
|
||||
}
|
||||
|
||||
private void doView( int indx ) {
|
||||
String path = fileList()[indx];
|
||||
File file = new File( path );
|
||||
Uri uri = Uri.fromFile( file );
|
||||
private void doView( String path )
|
||||
{
|
||||
Uri uri = Uri.fromFile( new File(path) );
|
||||
|
||||
Intent intent = new Intent( Intent.ACTION_EDIT, uri,
|
||||
GamesList.this, GameConfig.class );
|
||||
startActivity( intent );
|
||||
}
|
||||
|
||||
private String newName()
|
||||
{
|
||||
String name = null;
|
||||
Integer num = 0;
|
||||
int ii;
|
||||
String[] files = fileList();
|
||||
|
||||
while ( name == null ) {
|
||||
name = "game " + num.toString();
|
||||
for ( ii = 0; ii < files.length; ++ii ) {
|
||||
Utils.logf( "comparing " + name + " with " + files[ii] );
|
||||
if ( files[ii].equals(name) ) {
|
||||
++num;
|
||||
name = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
private void saveNew( CurGameInfo gi )
|
||||
{
|
||||
byte[] bytes = XwJNI.gi_to_stream( gi );
|
||||
if ( null != bytes ) {
|
||||
String name = newName();
|
||||
Utils.saveGame( this, bytes, newName() );
|
||||
Utils.saveGame( this, bytes );
|
||||
} else {
|
||||
Utils.logf( "gi_to_stream=>null" );
|
||||
}
|
||||
|
|
|
@ -7,8 +7,13 @@ import java.lang.Thread;
|
|||
import java.text.MessageFormat;
|
||||
import android.widget.Toast;
|
||||
import android.content.Context;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.util.ArrayList;
|
||||
import android.content.res.AssetManager;
|
||||
import android.os.Environment;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class Utils {
|
||||
static final String TAG = "EJAVA";
|
||||
|
@ -43,7 +48,6 @@ public class Utils {
|
|||
try {
|
||||
FileInputStream in = context.openFileInput( path );
|
||||
int len = in.available();
|
||||
Utils.logf( "savedGame: got " + len + " bytes." );
|
||||
stream = new byte[len];
|
||||
in.read( stream, 0, len );
|
||||
in.close();
|
||||
|
@ -69,5 +73,107 @@ public class Utils {
|
|||
}
|
||||
}
|
||||
|
||||
public static void saveGame( Context context, byte[] bytes )
|
||||
{
|
||||
saveGame( context, bytes, newName( context ) );
|
||||
}
|
||||
|
||||
public static String newName( Context context )
|
||||
{
|
||||
String name = null;
|
||||
Integer num = 0;
|
||||
int ii;
|
||||
String[] files = context.fileList();
|
||||
|
||||
while ( name == null ) {
|
||||
name = "game " + num.toString();
|
||||
for ( ii = 0; ii < files.length; ++ii ) {
|
||||
if ( files[ii].equals(name) ) {
|
||||
++num;
|
||||
name = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
private static void tryFile( ArrayList<String> al, String name )
|
||||
{
|
||||
if ( name.endsWith( ".xwd" ) ) {
|
||||
al.add( name );
|
||||
}
|
||||
}
|
||||
|
||||
private static void tryDir( ArrayList<String> al, File dir )
|
||||
{
|
||||
for ( File file: dir.listFiles() ) {
|
||||
tryFile( al, file.getAbsolutePath() );
|
||||
}
|
||||
}
|
||||
|
||||
public static String[] listDicts( Context context )
|
||||
{
|
||||
ArrayList<String> al = new ArrayList<String>();
|
||||
|
||||
try {
|
||||
AssetManager am = context.getAssets();
|
||||
String[] files = am.list("");
|
||||
for ( String file : files ) {
|
||||
tryFile( al, file );
|
||||
}
|
||||
} catch( java.io.IOException ioe ) {
|
||||
Utils.logf( ioe.toString() );
|
||||
}
|
||||
|
||||
File files[] = Environment.getExternalStorageDirectory().listFiles();
|
||||
for ( File file : files ) {
|
||||
if ( file.isDirectory() ) { // go down one level
|
||||
tryDir( al, file );
|
||||
} else {
|
||||
tryFile( al, file.getAbsolutePath() );
|
||||
}
|
||||
}
|
||||
|
||||
return al.toArray( new String[al.size()] );
|
||||
}
|
||||
|
||||
public static byte[] openDict( Context context, String name )
|
||||
{
|
||||
byte[] bytes = null;
|
||||
InputStream dict = null;
|
||||
AssetManager am = context.getAssets();
|
||||
try {
|
||||
dict = am.open( name,
|
||||
android.content.res.AssetManager.ACCESS_RANDOM );
|
||||
|
||||
int len = dict.available();
|
||||
bytes = new byte[len];
|
||||
int nRead = dict.read( bytes, 0, len );
|
||||
if ( nRead != len ) {
|
||||
Utils.logf( "**** warning ****; read only " + nRead + " of "
|
||||
+ len + " bytes." );
|
||||
}
|
||||
} catch ( java.io.IOException ee ){
|
||||
Utils.logf( "failed to open" );
|
||||
}
|
||||
|
||||
// not an asset? Try storage
|
||||
if ( null == bytes ) {
|
||||
try {
|
||||
FileInputStream fis = new FileInputStream( new File(name) );
|
||||
int len = fis.available();
|
||||
bytes = new byte[len];
|
||||
fis.read( bytes, 0, len );
|
||||
fis.close();
|
||||
} catch ( java.io.FileNotFoundException fnf ) {
|
||||
Utils.logf( fnf.toString() );
|
||||
} catch ( java.io.IOException ioe ) {
|
||||
Utils.logf( ioe.toString() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
package org.eehouse.android.xw4.jni;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
|
||||
public interface DrawCtx {
|
||||
static final int CELL_NONE = 0x00;
|
||||
|
@ -27,18 +28,18 @@ public interface DrawCtx {
|
|||
int dfs );
|
||||
void measureRemText( Rect r, int nTilesLeft, int[] width, int[] height );
|
||||
void measureScoreText( Rect r, DrawScoreInfo dsi, int[] width, int[] height );
|
||||
void drawRemText( Rect rInner,Rect rOuter, int nTilesLeft, boolean focussed );
|
||||
void drawRemText( Rect rInner, Rect rOuter, int nTilesLeft, boolean focussed );
|
||||
void score_drawPlayer( Rect rInner, Rect rOuter, DrawScoreInfo dsi );
|
||||
|
||||
boolean drawCell( Rect rect, String text, Object[] bitmaps, int tile,
|
||||
boolean drawCell( Rect rect, String text, BitmapDrawable[] bitmaps, int tile,
|
||||
int owner, int bonus, int hintAtts, int flags );
|
||||
void drawBoardArrow ( Rect rect, int bonus, boolean vert, int hintAtts,
|
||||
int flags );
|
||||
boolean vertScrollBoard( Rect /*out*/ rect, int dist, int dfs );
|
||||
|
||||
boolean trayBegin ( Rect rect, int owner, int dfs );
|
||||
void drawTile( Rect rect, String text, Object[] bitmaps, int val, int flags );
|
||||
void drawTileMidDrag ( Rect rect, String text, Object[] bitmaps,
|
||||
void drawTile( Rect rect, String text, BitmapDrawable[] bitmaps, int val, int flags );
|
||||
void drawTileMidDrag ( Rect rect, String text, BitmapDrawable[] bitmaps,
|
||||
int val, int owner, int flags );
|
||||
void drawTileBack( Rect rect, int flags );
|
||||
void drawTrayDivider( Rect rect, int flags );
|
||||
|
|
|
@ -66,7 +66,7 @@ public class JNIThread extends Thread {
|
|||
m_stopped = true;
|
||||
handle( JNICmd.CMD_NONE ); // tickle it
|
||||
try {
|
||||
join();
|
||||
join(100); // wait up to 1/10 second
|
||||
} catch ( java.lang.InterruptedException ie ) {
|
||||
Utils.logf( "got InterruptedException: " + ie.toString() );
|
||||
}
|
||||
|
@ -176,6 +176,11 @@ public class JNIThread extends Thread {
|
|||
barr );
|
||||
break;
|
||||
case CMD_PEN_MOVE:
|
||||
QueueElem nextElem = m_queue.peek();
|
||||
if ( null != nextElem && nextElem.m_cmd == JNICmd.CMD_PEN_MOVE ) {
|
||||
Utils.logf( "dropping CMD_PEN_MOVE" );
|
||||
continue;
|
||||
}
|
||||
draw = XwJNI.board_handlePenMove( m_jniGamePtr,
|
||||
((Integer)args[0]).intValue(),
|
||||
((Integer)args[1]).intValue() );
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
package org.eehouse.android.xw4.jni;
|
||||
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
|
||||
public interface XW_UtilCtxt {
|
||||
static final int BONUS_NONE = 0;
|
||||
static final int BONUS_DOUBLE_LETTER = 1;
|
||||
|
@ -75,6 +77,10 @@ public interface XW_UtilCtxt {
|
|||
|
||||
void notifyGameOver();
|
||||
|
||||
BitmapDrawable makeBitmap( int width, int height, boolean[] colors );
|
||||
|
||||
String[] splitFaces( byte[] chars );
|
||||
|
||||
// Don't need this unless we have a scroll thumb to indicate position
|
||||
//void yOffsetChange( int oldOffset, int newOffset );
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* -*-mode: C; compile-command: "cd XWords4; ../scripts/ndkbuild.sh"; -*- */
|
||||
|
||||
#include <jni.h>
|
||||
#include <stdio.h>
|
||||
|
@ -7,9 +8,11 @@
|
|||
#include "xptypes.h"
|
||||
#include "dictnry.h"
|
||||
#include "strutils.h"
|
||||
#include "utilwrapper.h"
|
||||
|
||||
typedef struct _AndDictionaryCtxt {
|
||||
DictionaryCtxt super;
|
||||
XW_UtilCtxt* util;
|
||||
JNIEnv *env;
|
||||
XP_U8* bytes;
|
||||
} AndDictionaryCtxt;
|
||||
|
@ -77,36 +80,28 @@ andCountSpecials( AndDictionaryCtxt* ctxt )
|
|||
} /* andCountSpecials */
|
||||
|
||||
static XP_Bitmap
|
||||
andMakeBitmap( XP_U8** ptrp )
|
||||
andMakeBitmap( AndDictionaryCtxt* ctxt, XP_U8** ptrp )
|
||||
{
|
||||
XP_U8* ptr = *ptrp;
|
||||
XP_U8 nCols = *ptr++;
|
||||
XP_Bitmap bitmap = NULL;
|
||||
/* CEBitmapInfo* bitmap = (CEBitmapInfo*)NULL; */
|
||||
jobject bitmap = NULL;
|
||||
|
||||
if ( nCols > 0 ) {
|
||||
XP_ASSERT(0);
|
||||
#if 0
|
||||
XP_U8* dest;
|
||||
XP_U8* savedDest;
|
||||
XP_U8 nRows = *ptr++;
|
||||
XP_U16 rowBytes = (nCols+7) / 8;
|
||||
XP_U8 srcByte = 0;
|
||||
XP_U8 destByte = 0;
|
||||
XP_U8 nBits;
|
||||
XP_U16 i;
|
||||
XP_U16 ii;
|
||||
|
||||
bitmap = (CEBitmapInfo*)XP_CALLOC( ctxt->super.mpool,
|
||||
sizeof(bitmap) );
|
||||
bitmap->nCols = nCols;
|
||||
bitmap->nRows = nRows;
|
||||
dest = XP_MALLOC( ctxt->super.mpool, rowBytes * nRows );
|
||||
bitmap->bits = savedDest = dest;
|
||||
jboolean* colors = (jboolean*)XP_CALLOC( ctxt->super.mpool,
|
||||
nCols * nRows * sizeof(*colors) );
|
||||
jboolean* next = colors;
|
||||
|
||||
nBits = nRows * nCols;
|
||||
for ( i = 0; i < nBits; ++i ) {
|
||||
XP_U8 srcBitIndex = i % 8;
|
||||
XP_U8 destBitIndex = (i % nCols) % 8;
|
||||
for ( ii = 0; ii < nBits; ++ii ) {
|
||||
XP_U8 srcBitIndex = ii % 8;
|
||||
XP_U8 destBitIndex = (ii % nCols) % 8;
|
||||
XP_U8 srcMask, bit;
|
||||
|
||||
if ( srcBitIndex == 0 ) {
|
||||
|
@ -114,38 +109,22 @@ andMakeBitmap( XP_U8** ptrp )
|
|||
}
|
||||
|
||||
srcMask = 1 << (7 - srcBitIndex);
|
||||
bit = (srcByte & srcMask) != 0;
|
||||
destByte |= bit << (7 - destBitIndex);
|
||||
|
||||
/* we need to put the byte if we've filled it or if we're done
|
||||
with the row */
|
||||
if ( (destBitIndex==7) || ((i%nCols) == (nCols-1)) ) {
|
||||
*dest++ = destByte;
|
||||
destByte = 0;
|
||||
}
|
||||
XP_ASSERT( next < (colors + (nRows * nCols)) );
|
||||
*next++ = ((srcByte & srcMask) == 0) ? JNI_FALSE : JNI_TRUE;
|
||||
}
|
||||
|
||||
/* printBitmapData1( nCols, nRows, savedDest ); */
|
||||
/* printBitmapData2( nCols, nRows, savedDest ); */
|
||||
#endif
|
||||
JNIEnv* env = ctxt->env;
|
||||
bitmap = and_util_makeJBitmap( ctxt->util, nCols, nRows, colors );
|
||||
jobject tmp = (*env)->NewGlobalRef( env, bitmap );
|
||||
XP_ASSERT( tmp == bitmap );
|
||||
(*env)->DeleteLocalRef( env, bitmap );
|
||||
XP_FREE( ctxt->super.mpool, colors );
|
||||
}
|
||||
|
||||
*ptrp = ptr;
|
||||
return (XP_Bitmap)bitmap;
|
||||
} /* andMakeBitmap */
|
||||
|
||||
static void
|
||||
andDeleteBitmap( const AndDictionaryCtxt* XP_UNUSED_DBG(ctxt),
|
||||
XP_Bitmap* bitmap )
|
||||
{
|
||||
if ( !!bitmap ) {
|
||||
XP_ASSERT(0);
|
||||
/* CEBitmapInfo* bmi = (CEBitmapInfo*)bitmap; */
|
||||
/* XP_FREE( ctxt->super.mpool, bmi->bits ); */
|
||||
/* XP_FREE( ctxt->super.mpool, bmi ); */
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
andLoadSpecialData( AndDictionaryCtxt* ctxt, XP_U8** ptrp )
|
||||
{
|
||||
|
@ -170,11 +149,11 @@ andLoadSpecialData( AndDictionaryCtxt* ctxt, XP_U8** ptrp )
|
|||
XP_MEMCPY( text, ptr, txtlen );
|
||||
ptr += txtlen;
|
||||
text[txtlen] = '\0';
|
||||
XP_ASSERT( *facep < nSpecials );
|
||||
XP_ASSERT( *facep < nSpecials ); /* firing */
|
||||
texts[(int)*facep] = text;
|
||||
|
||||
bitmaps[(int)*facep].largeBM = andMakeBitmap( &ptr );
|
||||
bitmaps[(int)*facep].smallBM = andMakeBitmap( &ptr );
|
||||
bitmaps[(int)*facep].largeBM = andMakeBitmap( ctxt, &ptr );
|
||||
bitmaps[(int)*facep].smallBM = andMakeBitmap( ctxt, &ptr );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,12 +163,69 @@ andLoadSpecialData( AndDictionaryCtxt* ctxt, XP_U8** ptrp )
|
|||
*ptrp = ptr;
|
||||
} /* andLoadSpecialData */
|
||||
|
||||
/** Android doesn't include iconv for C code to use, so we'll have java do it.
|
||||
* Cons up a string with all the tile faces (skipping the specials to make
|
||||
* things easier) and have java return an array of strings. Then load one at
|
||||
* a time into the expected null-separated format.
|
||||
*/
|
||||
static void
|
||||
splitFaces_via_java( JNIEnv* env, AndDictionaryCtxt* ctxt, const XP_U8* ptr,
|
||||
int nFaceBytes, int nFaces )
|
||||
{
|
||||
XP_UCHAR facesBuf[nFaces*4]; /* seems a reasonable upper bound... */
|
||||
int indx = 0;
|
||||
int offsets[nFaces];
|
||||
int nBytes;
|
||||
int ii;
|
||||
|
||||
jobject jstrarr = and_util_splitFaces( ctxt->util, ptr, nFaceBytes );
|
||||
XP_ASSERT( (*env)->GetArrayLength( env, jstrarr ) == nFaces );
|
||||
|
||||
for ( ii = 0; ii < nFaces; ++ii ) {
|
||||
jobject jstr = (*env)->GetObjectArrayElement( env, jstrarr, ii );
|
||||
offsets[ii] = indx;
|
||||
nBytes = (*env)->GetStringUTFLength( env, jstr );
|
||||
|
||||
const char* bytes = (*env)->GetStringUTFChars( env, jstr, NULL );
|
||||
char* end;
|
||||
long numval = strtol( bytes, &end, 10 );
|
||||
if ( end > bytes ) {
|
||||
XP_ASSERT( numval < 32 );
|
||||
nBytes = 1;
|
||||
facesBuf[indx] = (XP_UCHAR)numval;
|
||||
} else {
|
||||
XP_MEMCPY( &facesBuf[indx], bytes, nBytes );
|
||||
}
|
||||
(*env)->ReleaseStringUTFChars( env, jstr, bytes );
|
||||
(*env)->DeleteLocalRef( env, jstr );
|
||||
|
||||
indx += nBytes;
|
||||
facesBuf[indx++] = '\0';
|
||||
XP_ASSERT( indx < VSIZE(facesBuf) );
|
||||
}
|
||||
(*env)->DeleteLocalRef( env, jstrarr );
|
||||
|
||||
XP_UCHAR* faces = (XP_UCHAR*)XP_CALLOC( ctxt->super.mpool, indx );
|
||||
XP_UCHAR** ptrs = (XP_UCHAR**)XP_CALLOC( ctxt->super.mpool,
|
||||
nFaces * sizeof(ptrs[0]));
|
||||
|
||||
XP_MEMCPY( faces, facesBuf, indx );
|
||||
for ( ii = 0; ii < nFaces; ++ii ) {
|
||||
ptrs[ii] = &faces[offsets[ii]];
|
||||
}
|
||||
|
||||
XP_ASSERT( !ctxt->super.faces );
|
||||
ctxt->super.faces = faces;
|
||||
XP_ASSERT( !ctxt->super.facePtrs );
|
||||
ctxt->super.facePtrs = ptrs;
|
||||
} /* splitFaces_via_java */
|
||||
|
||||
static void
|
||||
parseDict( AndDictionaryCtxt* ctxt, XP_U8* ptr, XP_U32 dictLength )
|
||||
{
|
||||
while( !!ptr ) { /* lets us break.... */
|
||||
XP_U32 offset;
|
||||
XP_U16 numFaces, numFaceBytes = 0;
|
||||
XP_U16 nFaces, numFaceBytes = 0;
|
||||
XP_U16 i;
|
||||
XP_U16 flags;
|
||||
void* mappedBase = (void*)ptr;
|
||||
|
@ -198,7 +234,6 @@ parseDict( AndDictionaryCtxt* ctxt, XP_U8* ptr, XP_U32 dictLength )
|
|||
|
||||
flags = n_ptr_tohs( &ptr );
|
||||
|
||||
#ifdef NODE_CAN_4
|
||||
if ( flags == 0x0002 ) {
|
||||
nodeSize = 3;
|
||||
} else if ( flags == 0x0003 ) {
|
||||
|
@ -212,38 +247,33 @@ parseDict( AndDictionaryCtxt* ctxt, XP_U8* ptr, XP_U32 dictLength )
|
|||
} else {
|
||||
break; /* we want to return NULL */
|
||||
}
|
||||
#else
|
||||
if( flags != 0x0001 ) {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( isUTF8 ) {
|
||||
numFaceBytes = (XP_U16)(*ptr++);
|
||||
}
|
||||
numFaces = (XP_U16)(*ptr++);
|
||||
if ( numFaces > 64 ) {
|
||||
nFaces = (XP_U16)(*ptr++);
|
||||
if ( nFaces > 64 ) {
|
||||
break;
|
||||
}
|
||||
|
||||
ctxt->super.nodeSize = nodeSize;
|
||||
|
||||
if ( !isUTF8 ) {
|
||||
numFaceBytes = numFaces * 2;
|
||||
numFaceBytes = nFaces * 2;
|
||||
}
|
||||
|
||||
ctxt->super.nFaces = (XP_U8)numFaces;
|
||||
ctxt->super.nFaces = (XP_U8)nFaces;
|
||||
ctxt->super.isUTF8 = isUTF8;
|
||||
|
||||
if ( isUTF8 ) {
|
||||
XP_ASSERT(0);
|
||||
dict_splitFaces( &ctxt->super, ptr, numFaceBytes, numFaces );
|
||||
splitFaces_via_java( ctxt->env, ctxt, ptr, numFaceBytes, nFaces );
|
||||
ptr += numFaceBytes;
|
||||
} else {
|
||||
XP_U8 tmp[numFaces*4]; /* should be enough... */
|
||||
XP_U8 tmp[nFaces*4]; /* should be enough... */
|
||||
XP_U16 nBytes = 0;
|
||||
XP_U16 ii;
|
||||
/* Need to translate from iso-8859-n to utf8 */
|
||||
for ( ii = 0; ii < numFaces; ++ii ) {
|
||||
for ( ii = 0; ii < nFaces; ++ii ) {
|
||||
XP_UCHAR ch = ptr[1];
|
||||
|
||||
ptr += 2;
|
||||
|
@ -251,16 +281,16 @@ parseDict( AndDictionaryCtxt* ctxt, XP_U8* ptr, XP_U32 dictLength )
|
|||
tmp[nBytes] = ch;
|
||||
nBytes += 1;
|
||||
}
|
||||
dict_splitFaces( &ctxt->super, tmp, nBytes, numFaces );
|
||||
dict_splitFaces( &ctxt->super, tmp, nBytes, nFaces );
|
||||
}
|
||||
|
||||
ctxt->super.is_4_byte = (ctxt->super.nodeSize == 4);
|
||||
|
||||
ctxt->super.countsAndValues =
|
||||
(XP_U8*)XP_MALLOC(ctxt->super.mpool, numFaces*2);
|
||||
(XP_U8*)XP_MALLOC(ctxt->super.mpool, nFaces*2);
|
||||
|
||||
ptr += 2; /* skip xloc header */
|
||||
for ( i = 0; i < numFaces*2; i += 2 ) {
|
||||
for ( i = 0; i < nFaces*2; i += 2 ) {
|
||||
ctxt->super.countsAndValues[i] = *ptr++;
|
||||
ctxt->super.countsAndValues[i+1] = *ptr++;
|
||||
}
|
||||
|
@ -324,11 +354,12 @@ and_dictionary_destroy( DictionaryCtxt* dict )
|
|||
XP_FREE( ctxt->super.mpool, ctxt->super.chars );
|
||||
}
|
||||
if ( !!ctxt->super.bitmaps ) {
|
||||
JNIEnv* env = ctxt->env;
|
||||
for ( ii = 0; ii < nSpecials; ++ii ) {
|
||||
XP_ASSERT( !ctxt->super.bitmaps[ii].largeBM );
|
||||
XP_ASSERT( !ctxt->super.bitmaps[ii].smallBM );
|
||||
andDeleteBitmap( ctxt, ctxt->super.bitmaps[ii].largeBM );
|
||||
andDeleteBitmap( ctxt, ctxt->super.bitmaps[ii].smallBM );
|
||||
jobject bitmap = ctxt->super.bitmaps[ii].largeBM;
|
||||
if ( !!bitmap ) {
|
||||
(*env)->DeleteGlobalRef( env, bitmap );
|
||||
}
|
||||
}
|
||||
XP_FREE( ctxt->super.mpool, ctxt->super.bitmaps );
|
||||
}
|
||||
|
@ -345,7 +376,7 @@ and_dictionary_destroy( DictionaryCtxt* dict )
|
|||
}
|
||||
|
||||
DictionaryCtxt*
|
||||
makeDict( MPFORMAL JNIEnv *env, jbyteArray jbytes )
|
||||
makeDict( MPFORMAL JNIEnv *env, XW_UtilCtxt* util, jbyteArray jbytes )
|
||||
{
|
||||
XP_Bool formatOk = XP_TRUE;
|
||||
XP_Bool isUTF8 = XP_FALSE;
|
||||
|
@ -368,6 +399,7 @@ makeDict( MPFORMAL JNIEnv *env, jbyteArray jbytes )
|
|||
MPASSIGN(anddict->super.mpool, mpool);
|
||||
anddict->bytes = localBytes;
|
||||
anddict->env = env;
|
||||
anddict->util = util;
|
||||
|
||||
parseDict( anddict, localBytes, len );
|
||||
setBlankTile( &anddict->super );
|
||||
|
|
|
@ -9,7 +9,8 @@ void
|
|||
dict_splitFaces( DictionaryCtxt* dict, const XP_U8* bytes,
|
||||
XP_U16 nBytes, XP_U16 nFaces );
|
||||
|
||||
DictionaryCtxt* makeDict( MPFORMAL JNIEnv *env, jbyteArray bytes );
|
||||
DictionaryCtxt* makeDict( MPFORMAL JNIEnv *env, XW_UtilCtxt* util,
|
||||
jbyteArray bytes );
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -185,6 +185,20 @@ makeIntArray( JNIEnv *env, int siz, const jint* vals )
|
|||
return array;
|
||||
}
|
||||
|
||||
jbooleanArray
|
||||
makeBooleanArray( JNIEnv *env, int siz, const jboolean* vals )
|
||||
{
|
||||
jbooleanArray array = (*env)->NewBooleanArray( env, siz );
|
||||
XP_ASSERT( !!array );
|
||||
if ( !!vals ) {
|
||||
jboolean* elems = (*env)->GetBooleanArrayElements( env, array, NULL );
|
||||
XP_ASSERT( !!elems );
|
||||
XP_MEMCPY( elems, vals, siz * sizeof(*elems) );
|
||||
(*env)->ReleaseBooleanArrayElements( env, array, elems, 0 );
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
int
|
||||
getIntFromArray( JNIEnv* env, jintArray arr, bool del )
|
||||
{
|
||||
|
@ -241,3 +255,24 @@ getMethodID( JNIEnv* env, jobject obj, const char* proc, const char* sig )
|
|||
(*env)->DeleteLocalRef( env, cls );
|
||||
return mid;
|
||||
}
|
||||
|
||||
jobjectArray
|
||||
makeBitmapsArray( JNIEnv* env, const XP_Bitmaps* bitmaps )
|
||||
{
|
||||
jobjectArray result = NULL;
|
||||
|
||||
if ( !!bitmaps && bitmaps->nBitmaps > 0 ) {
|
||||
jclass clazz = (*env)->FindClass( env,
|
||||
"android/graphics/drawable/BitmapDrawable" );
|
||||
XP_ASSERT( !!clazz );
|
||||
result = (*env)->NewObjectArray( env, bitmaps->nBitmaps, clazz, NULL );
|
||||
(*env)->DeleteLocalRef( env, clazz );
|
||||
|
||||
int ii;
|
||||
for ( ii = 0; ii < bitmaps->nBitmaps; ++ii ) {
|
||||
(*env)->SetObjectArrayElement( env, result, ii, bitmaps->bmps[ii] );
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "comtypes.h"
|
||||
#include "mempool.h"
|
||||
#include "dictnry.h"
|
||||
|
||||
XP_U32 and_ntohl(XP_U32 l);
|
||||
XP_U16 and_ntohs(XP_U16 l);
|
||||
|
@ -26,9 +27,13 @@ bool getObject( JNIEnv* env, jobject obj, const char* name, const char* sig,
|
|||
jintArray makeIntArray( JNIEnv *env, int size, const jint* vals );
|
||||
int getIntFromArray( JNIEnv* env, jintArray arr, bool del );
|
||||
|
||||
jbooleanArray makeBooleanArray( JNIEnv *env, int size, const jboolean* vals );
|
||||
|
||||
jobjectArray makeStringArray( JNIEnv *env, int size, const XP_UCHAR** vals );
|
||||
jstring streamToJString( MPFORMAL JNIEnv* env, XWStreamCtxt* stream );
|
||||
|
||||
jobjectArray makeBitmapsArray( JNIEnv* env, const XP_Bitmaps* bitmaps );
|
||||
|
||||
/* Note: jmethodID can be cached. Should not look up more than once. */
|
||||
jmethodID getMethodID( JNIEnv* env, jobject obj, const char* proc,
|
||||
const char* sig );
|
||||
|
|
|
@ -222,27 +222,28 @@ and_draw_drawCell( DrawCtx* dctx, const XP_Rect* rect, const XP_UCHAR* text,
|
|||
const XP_Bitmaps* bitmaps, Tile tile, XP_S16 owner,
|
||||
XWBonusType bonus, HintAtts hintAtts, CellFlags flags )
|
||||
{
|
||||
DRAW_CBK_HEADER("drawCell",
|
||||
"(Landroid/graphics/Rect;Ljava/lang/String;"
|
||||
"[Ljava/lang/Object;IIIII)Z" );
|
||||
|
||||
DRAW_CBK_HEADER("drawCell", "(Landroid/graphics/Rect;Ljava/lang/String;"
|
||||
"[Landroid/graphics/drawable/BitmapDrawable;IIIII)Z" );
|
||||
jobject jrect = makeJRect( env, rect );
|
||||
jstring jtext = NULL;
|
||||
if ( !!text ) {
|
||||
jtext = (*env)->NewStringUTF( env, text );
|
||||
}
|
||||
|
||||
jobjectArray jbitmaps = !!bitmaps ? makeBitmapsArray( env, bitmaps ) : NULL;
|
||||
jboolean result = (*env)->CallBooleanMethod( env, draw->j_draw, mid,
|
||||
jrect, jtext, NULL, tile,
|
||||
jrect, jtext, jbitmaps, tile,
|
||||
owner, bonus, hintAtts,
|
||||
flags );
|
||||
|
||||
(*env)->DeleteLocalRef( env, jrect );
|
||||
if ( !!jtext ) {
|
||||
(*env)->DeleteLocalRef( env, jtext );
|
||||
}
|
||||
if ( !!jbitmaps ) {
|
||||
(*env)->DeleteLocalRef( env, jbitmaps );
|
||||
}
|
||||
|
||||
return XP_TRUE;
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -293,21 +294,24 @@ and_draw_drawTile( DrawCtx* dctx, const XP_Rect* rect, const XP_UCHAR* text,
|
|||
const XP_Bitmaps* bitmaps, XP_U16 val, CellFlags flags )
|
||||
{
|
||||
DRAW_CBK_HEADER( "drawTile", "(Landroid/graphics/Rect;Ljava/lang/String;"
|
||||
"[Ljava/lang/Object;II)V" );
|
||||
|
||||
"[Landroid/graphics/drawable/BitmapDrawable;II)V" );
|
||||
jobject jrect = makeJRect( env, rect );
|
||||
jstring jtext = NULL;
|
||||
if ( !!text ) {
|
||||
jtext = (*env)->NewStringUTF( env, text );
|
||||
}
|
||||
|
||||
jobjectArray jbitmaps = makeBitmapsArray( env, bitmaps );
|
||||
(*env)->CallVoidMethod( env, draw->j_draw, mid,
|
||||
jrect, jtext, NULL, val, flags );
|
||||
jrect, jtext, jbitmaps, val, flags );
|
||||
|
||||
(*env)->DeleteLocalRef( env, jrect );
|
||||
if ( !!jtext ) {
|
||||
(*env)->DeleteLocalRef( env, jtext );
|
||||
}
|
||||
if ( !!jbitmaps ) {
|
||||
(*env)->DeleteLocalRef( env, jbitmaps );
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -316,7 +320,7 @@ and_draw_drawTileMidDrag( DrawCtx* dctx, const XP_Rect* rect,
|
|||
XP_U16 val, XP_U16 owner, CellFlags flags )
|
||||
{
|
||||
DRAW_CBK_HEADER( "drawTileMidDrag", "(Landroid/graphics/Rect;Ljava/lang/String;"
|
||||
"[Ljava/lang/Object;III)V" );
|
||||
"[Landroid/graphics/drawable/BitmapDrawable;III)V" );
|
||||
|
||||
jobject jrect = makeJRect( env, rect );
|
||||
jstring jtext = NULL;
|
||||
|
@ -324,13 +328,17 @@ and_draw_drawTileMidDrag( DrawCtx* dctx, const XP_Rect* rect,
|
|||
jtext = (*env)->NewStringUTF( env, text );
|
||||
}
|
||||
|
||||
jobjectArray jbitmaps = makeBitmapsArray( env, bitmaps );
|
||||
(*env)->CallVoidMethod( env, draw->j_draw, mid,
|
||||
jrect, jtext, NULL, val, owner, flags );
|
||||
jrect, jtext, jbitmaps, val, owner, flags );
|
||||
|
||||
(*env)->DeleteLocalRef( env, jrect );
|
||||
if ( !!jtext ) {
|
||||
(*env)->DeleteLocalRef( env, jtext );
|
||||
}
|
||||
if ( !!jbitmaps ) {
|
||||
(*env)->DeleteLocalRef( env, jbitmaps );
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -73,6 +73,11 @@ and_util_userError( XW_UtilCtxt* uc, UtilErrID id )
|
|||
{
|
||||
UTIL_CBK_HEADER( "userError", "(I)V" );
|
||||
(*env)->CallVoidMethod( env, util->j_util, mid, id );
|
||||
if ((*env)->ExceptionOccurred(env)) {
|
||||
(*env)->ExceptionDescribe(env);
|
||||
(*env)->ExceptionClear(env);
|
||||
XP_LOGF( "exception found" );
|
||||
}
|
||||
}
|
||||
|
||||
static XP_Bool
|
||||
|
@ -313,6 +318,40 @@ and_util_engineStopping( XW_UtilCtxt* uc )
|
|||
}
|
||||
#endif
|
||||
|
||||
/* These are called from anddict.c, not via vtable */
|
||||
jobject
|
||||
and_util_makeJBitmap( XW_UtilCtxt* uc, int nCols, int nRows,
|
||||
const jboolean* colors )
|
||||
{
|
||||
jobject bitmap;
|
||||
UTIL_CBK_HEADER( "makeBitmap",
|
||||
"(II[Z)Landroid/graphics/drawable/BitmapDrawable;" );
|
||||
jbooleanArray jcolors = makeBooleanArray( env, nCols*nRows, colors );
|
||||
|
||||
bitmap = (*env)->CallObjectMethod( env, util->j_util, mid,
|
||||
nCols, nRows, jcolors );
|
||||
(*env)->DeleteLocalRef( env, jcolors );
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
jobject
|
||||
and_util_splitFaces( XW_UtilCtxt* uc, const XP_U8* bytes, jsize len )
|
||||
{
|
||||
jobject strarray;
|
||||
UTIL_CBK_HEADER( "splitFaces", "([B)[Ljava/lang/String;" );
|
||||
|
||||
jbyteArray jbytes = (*env)->NewByteArray( env, len );
|
||||
|
||||
jbyte* jp = (*env)->GetByteArrayElements( env, jbytes, NULL );
|
||||
XP_MEMCPY( jp, bytes, len );
|
||||
(*env)->ReleaseByteArrayElements( env, jbytes, jp, 0 );
|
||||
|
||||
strarray = (*env)->CallObjectMethod( env, util->j_util, mid, jbytes );
|
||||
(*env)->DeleteLocalRef( env, jbytes );
|
||||
|
||||
return strarray;
|
||||
}
|
||||
|
||||
|
||||
XW_UtilCtxt*
|
||||
makeUtil( MPFORMAL JNIEnv** envp, jobject j_util, CurGameInfo* gi,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* -*-mode: C; fill-column: 76; c-basic-offset: 4; -*- */
|
||||
/*
|
||||
* Copyright 2001-2009 by Eric House (xwords@eehouse.org). All rights
|
||||
* Copyright 2001-2010 by Eric House (xwords@eehouse.org). All rights
|
||||
* reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -33,5 +33,8 @@ void destroyUtil( XW_UtilCtxt* util );
|
|||
|
||||
bool utilTimerFired( XW_UtilCtxt* util, XWTimerReason why, int handle );
|
||||
|
||||
jobject and_util_makeJBitmap( XW_UtilCtxt* util, int nCols, int nRows,
|
||||
const jboolean* colors );
|
||||
jobject and_util_splitFaces( XW_UtilCtxt* uc, const XP_U8* bytes, int len );
|
||||
|
||||
#endif
|
||||
|
|
|
@ -271,7 +271,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeNewGame
|
|||
game_makeNewGame( MPPARM(mpool) &state->game, gi, util, dctx, gameID,
|
||||
&cp, NULL );
|
||||
|
||||
DictionaryCtxt* dict = makeDict( MPPARM(mpool) env, jDictBytes );
|
||||
DictionaryCtxt* dict = makeDict( MPPARM(mpool) env, util, jDictBytes );
|
||||
#ifdef STUBBED_DICT
|
||||
if ( !dict ) {
|
||||
XP_LOGF( "falling back to stubbed dict" );
|
||||
|
@ -319,8 +319,8 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeFromStream
|
|||
XWJNI_START();
|
||||
|
||||
globals->gi = (CurGameInfo*)XP_CALLOC( mpool, sizeof(*globals->gi) );
|
||||
DictionaryCtxt* dict = makeDict( MPPARM(mpool) env, jdict );
|
||||
globals->util = makeUtil( MPPARM(mpool) &state->env, jutil, globals->gi, globals );
|
||||
DictionaryCtxt* dict = makeDict( MPPARM(mpool) env, globals->util, jdict );
|
||||
globals->dctx = makeDraw( MPPARM(mpool) &state->env, jdraw );
|
||||
|
||||
jbyte* jelems = (*env)->GetByteArrayElements( env, jstream, NULL );
|
||||
|
@ -342,8 +342,8 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeFromStream
|
|||
setJGI( env, jgi, globals->gi );
|
||||
} else {
|
||||
destroyDraw( globals->dctx );
|
||||
destroyUtil( globals->util );
|
||||
dict_destroy( dict );
|
||||
destroyUtil( globals->util );
|
||||
destroyGI( MPPARM(mpool) globals->gi );
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue