Merge remote branch 'origin/android_branch' into android_branch

This commit is contained in:
Eric House 2014-04-23 07:40:46 -07:00
commit 6a4c599da5
25 changed files with 503 additions and 221 deletions

View file

@ -22,7 +22,7 @@
to come from a domain that you own or have control over. -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.eehouse.android.xw4"
android:versionCode="75"
android:versionCode="76"
android:versionName="@string/app_version"
>

View file

@ -49,7 +49,7 @@
<!-- extension targets. Uncomment the ones where you want to do custom work
in between standard targets -->
<property name="INITIAL_CLIENT_VERS" value="3"/>
<property name="INITIAL_CLIENT_VERS" value="4"/>
<target name="-pre-clean">
<exec dir="." executable="../scripts/ndksetup.sh" output="/dev/null"
failonerror="true" >

View file

@ -6,10 +6,10 @@
android:layout_height="fill_parent"
>
<ExpandableListView android:id="@id/android:list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:drawSelectorOnTop="false"
/>
<ListView android:id="@id/android:list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:drawSelectorOnTop="false"
/>
</LinearLayout>

View file

@ -1,15 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<org.eehouse.android.xw4.GameListGroup
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/game_name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="right"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceMedium"
android:paddingTop="3dp"
android:paddingBottom="3dp"
android:textStyle="italic"
android:background="#FF7F7F7F"
/>
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"
android:background="#FF7F7F7F"
>
<TextView android:id="@+id/game_name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="left"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceMedium"
android:paddingTop="3dp"
android:paddingBottom="3dp"
android:textStyle="italic"
android:layout_weight="1"
/>
<ImageButton android:id="@+id/expander"
style="@style/expander_button"
/>
</org.eehouse.android.xw4.GameListGroup>

View file

@ -70,9 +70,7 @@
/>
<ImageButton android:id="@+id/expander"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@drawable/expander_ic_maximized"
style="@style/expander_button"
/>
</LinearLayout>

View file

@ -5,20 +5,16 @@
</style>
</head>
<body>
<b>Crosswords 4.4 beta 82 release</b>
<b>Crosswords 4.4 beta 83 release</b>
<h3>New with this release</h3>
<ul>
<li>Add ability to select studylist items so subsets can be removed or copied out</li>
<li>Enable studylists by default for new installs</li>
<li>Fix bug with Wordlist browser selections</li>
<li>Improve Lookup/Add-to-studylist dialog</li>
<li>Fix bug clearing pending move when you long-tap a letter to see words it's in</li>
<li>Other performance and minor UI improvements</li>
<li>Bug fix (obscure): don't mangle unicode model names</li>
</ul>
<h3>Next up</h3>
<ul>
<li>Much better support for localization</li>
<li>Look, again, at play via Bluetooth now that HTC phones aren't quite so common</li>
<li>Fix SMS play for KitKat</li>
<li>Offer "Rematch" when game's over</li>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_version">4.4 beta 82</string>
<string name="app_version">4.4 beta 83</string>
</resources>

View file

@ -66,5 +66,11 @@
<item name="android:layout_weight">1</item>
</style>
<style name="expander_button">
<item name="android:layout_width">32dp</item>
<item name="android:layout_height">32dp</item>
<item name="android:src">@drawable/expander_ic_maximized</item>
</style>
</resources>

View file

@ -545,7 +545,7 @@ public class BoardDelegate extends DelegateBase
m_haveInvited = intent.getBooleanExtra( GameUtils.INVITED, false );
m_overNotShown = true;
NFCUtils.register( m_activity ); // Don't seem to need to unregister...
NFCUtils.register( m_activity, this ); // Don't seem to need to unregister...
setBackgroundColor();
setKeepScreenOn();

View file

@ -205,7 +205,7 @@ public class DBUtils {
int col = cursor.getColumnIndex( DBHelper.CONTYPE );
if ( 0 <= col ) {
tmp = cursor.getInt( col );
summary.conType = CommsConnType.values()[tmp];
summary.conType = CommsAddrRec.CommsConnType.values()[tmp];
col = cursor.getColumnIndex( DBHelper.SEED );
if ( 0 < col ) {
summary.seed = cursor.getInt( col );
@ -964,14 +964,16 @@ public class DBUtils {
// Groups stuff
public static class GameGroupInfo {
public String m_name;
public int m_count;
public boolean m_expanded;
public long m_lastMoveTime;
public boolean m_hasTurn;
public boolean m_turnLocal;
public GameGroupInfo( String name, boolean expanded ) {
public GameGroupInfo( String name, int count, boolean expanded ) {
m_name = name; m_expanded = expanded;
m_lastMoveTime = 0;
m_count = count;
}
}
@ -1010,44 +1012,58 @@ public class DBUtils {
return thumb;
}
// Return map of string (group name) to info about all games in
// that group.
public static HashMap<Long,GameGroupInfo> getGroups( Context context )
private static HashMap<Long, Integer> getGameCounts( SQLiteDatabase db )
{
return getGroups( context, 0 );
HashMap<Long, Integer> result = new HashMap<Long, Integer>();
String query = "SELECT %s, count(%s) as cnt FROM %s GROUP BY %s";
query = String.format( query, DBHelper.GROUPID, DBHelper.GROUPID,
DBHelper.TABLE_NAME_SUM, DBHelper.GROUPID );
Cursor cursor = db.rawQuery( query, null );
int rowIndex = cursor.getColumnIndex( DBHelper.GROUPID );
int cntIndex = cursor.getColumnIndex( "cnt" );
while ( cursor.moveToNext() ) {
long row = cursor.getLong(rowIndex);
int count = cursor.getInt(cntIndex);
result.put( row, count );
}
cursor.close();
return result;
}
private static HashMap<Long,GameGroupInfo> getGroups( Context context,
int nRows )
// Map of groups rowid (= summaries.groupid) to group info record
protected static HashMap<Long,GameGroupInfo> getGroups( Context context )
{
if ( null == s_groupsCache ) {
HashMap<Long,GameGroupInfo> result =
new HashMap<Long,GameGroupInfo>();
String[] columns = { ROW_ID, DBHelper.GROUPNAME,
DBHelper.EXPANDED };
String limit = 0 == nRows ? null : String.format( "%d", nRows );
// Select all groups. For each group get the number of games in
// that group. There should be a way to do that with one query
// but I can't figure it out.
String query = "SELECT rowid, groupname as groups_groupname, "
+ " groups.expanded as groups_expanded FROM groups";
DbgUtils.logf( "query: %s", query );
initDB( context );
synchronized( s_dbHelper ) {
SQLiteDatabase db = s_dbHelper.getReadableDatabase();
Cursor cursor = db.query( DBHelper.TABLE_NAME_GROUPS, columns,
null, // selection
null, // args
null, // groupBy
null, // having
null, //orderby
limit
);
int idIndex = cursor.getColumnIndex( ROW_ID );
int nameIndex = cursor.getColumnIndex( DBHelper.GROUPNAME );
int expandedIndex = cursor.getColumnIndex( DBHelper.EXPANDED );
HashMap<Long, Integer> map = getGameCounts( db );
Cursor cursor = db.rawQuery( query, null );
int idIndex = cursor.getColumnIndex( "rowid" );
int nameIndex = cursor.getColumnIndex( "groups_groupname" );
int expandedIndex = cursor.getColumnIndex( "groups_expanded" );
while ( cursor.moveToNext() ) {
String name = cursor.getString( nameIndex );
long id = cursor.getLong( idIndex );
String name = cursor.getString( nameIndex );
Assert.assertNotNull( name );
boolean expanded = 0 != cursor.getInt( expandedIndex );
result.put( id, new GameGroupInfo( name, expanded ) );
int count = map.containsKey( id ) ? map.get( id ) : 0;
result.put( id, new GameGroupInfo( name, count, expanded ) );
}
cursor.close();
@ -1136,6 +1152,28 @@ public class DBUtils {
}
}
public static int countGames( Context context )
{
int result = 0;
String[] columns = { ROW_ID };
initDB( context );
synchronized( s_dbHelper ) {
SQLiteDatabase db = s_dbHelper.getReadableDatabase();
Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns,
null, // selection
null, // args
null, // groupBy
null, // having
null
);
result = cursor.getCount();
cursor.close();
db.close();
}
DbgUtils.logf( "DBUtils.countGames()=>%d", result );
return result;
}
public static long[] getGroupGames( Context context, long groupID )
{
long[] result = null;
@ -1202,7 +1240,7 @@ public class DBUtils {
public static long getAnyGroup( Context context )
{
long result = GROUPID_UNSPEC;
HashMap<Long,GameGroupInfo> groups = getGroups( context, 1 );
HashMap<Long,GameGroupInfo> groups = getGroups( context );
Iterator<Long> iter = groups.keySet().iterator();
if ( iter.hasNext() ) {
result = iter.next();

View file

@ -0,0 +1,47 @@
/* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/*
* Copyright 2009-2014 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.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.view.View;
public class DrawSelDelegate {
private View m_view;
private Drawable m_origDrawable;
private static ColorDrawable s_selDrawable =
new ColorDrawable( XWApp.SEL_COLOR );
protected DrawSelDelegate( View view )
{
m_view = view;
}
protected void showSelected( boolean selected )
{
if ( selected ) {
m_origDrawable = m_view.getBackground();
m_view.setBackgroundDrawable( s_selDrawable );
} else {
m_view.setBackgroundDrawable( m_origDrawable );
}
}
}

View file

@ -52,12 +52,11 @@ public class ExpiringDelegate {
private long m_startSecs;
private Runnable m_runnable = null;
private boolean m_selected;
private Drawable m_origDrawable;
// these can be static as drawing's all in same thread.
private static Rect s_rect;
private static Paint s_paint;
private static float[] s_points;
private static Drawable s_selDrawable;
private DrawSelDelegate m_dsdel;
static {
s_rect = new Rect();
@ -65,14 +64,13 @@ public class ExpiringDelegate {
s_paint.setStyle(Paint.Style.STROKE);
s_paint.setStrokeWidth( 1 );
s_points = new float[4*6];
s_selDrawable = new ColorDrawable( XWApp.SEL_COLOR );
}
public ExpiringDelegate( Context context, View view )
{
m_context = context;
m_view = view;
m_origDrawable = view.getBackground();
m_dsdel = new DrawSelDelegate( view );
}
public void setHandler( Handler handler )
@ -101,12 +99,7 @@ public class ExpiringDelegate {
public void setSelected( boolean selected )
{
m_selected = selected;
if ( selected ) {
m_origDrawable = m_view.getBackground();
m_view.setBackgroundDrawable( s_selDrawable );
} else {
m_view.setBackgroundDrawable( m_origDrawable );
}
m_dsdel.showSelected( m_selected );
}
public void onDraw( Canvas canvas )

View file

@ -49,6 +49,8 @@ public class ExpiringLinearLayout extends LinearLayout {
protected void onDraw( Canvas canvas )
{
super.onDraw( canvas );
m_delegate.onDraw( canvas );
if ( null != m_delegate ) {
m_delegate.onDraw( canvas );
}
}
}

View file

@ -28,7 +28,6 @@ import android.widget.TextView;
class ExpiringTextView extends TextView {
private ExpiringDelegate m_delegate = null;
private Context m_context;
protected boolean m_selected = false;
public ExpiringTextView( Context context, AttributeSet attrs )
{
@ -53,12 +52,6 @@ class ExpiringTextView extends TextView {
}
}
protected void toggleSelected()
{
m_selected = !m_selected;
getDelegate().setSelected( m_selected );
}
@Override
protected void onDraw( Canvas canvas )
{

View file

@ -24,8 +24,8 @@ import android.database.DataSetObserver;
import android.os.Handler;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.ListAdapter;
import android.widget.ListView;
import java.util.Collections;
import java.util.HashMap; // class is not synchronized
@ -40,18 +40,21 @@ import org.eehouse.android.xw4.jni.CurGameInfo.DeviceRole;
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
import org.eehouse.android.xw4.DBUtils.GameGroupInfo;
public class GameListAdapter implements ExpandableListAdapter {
public class GameListAdapter extends XWListAdapter
implements GameListGroup.GroupStateListener {
private Context m_context;
private ExpandableListView m_list;
private ListView m_list;
private int m_fieldID;
private Handler m_handler;
private SelectableItem m_cb;
private long[] m_positions;
public GameListAdapter( Context context, ExpandableListView list,
public GameListAdapter( Context context, ListView list,
Handler handler, SelectableItem cb,
long[] positions, String fieldName )
{
super( 0 );
m_context = context;
m_list = list;
m_handler = handler;
@ -61,6 +64,23 @@ public class GameListAdapter implements ExpandableListAdapter {
m_fieldID = fieldToID( fieldName );
}
@Override
public int getCount()
{
HashMap<Long,GameGroupInfo> groups = DBUtils.getGroups( m_context );
int count = groups.size();
for ( GameGroupInfo ggi : groups.values() ) {
if ( ggi.m_expanded ) {
count += ggi.m_count;
}
}
// DbgUtils.logf( "GameListAdapter.getCount() => %d", count );
return count;
}
@Override
public int getViewTypeCount() { return 2; }
public long[] getGroupPositions()
{
Set<Long> keys = gameInfo().keySet(); // do not modify!!!!
@ -103,15 +123,16 @@ public class GameListAdapter implements ExpandableListAdapter {
return success;
}
public void expandGroups( ExpandableListView view )
public void expandGroups( ListView view )
{
HashMap<Long,GameGroupInfo> info = gameInfo();
for ( int ii = 0; ii < info.size(); ++ii ) {
GameGroupInfo ggi = getInfoForGroup( ii );
if ( ggi.m_expanded ) {
view.expandGroup( ii );
}
}
DbgUtils.logf( "expandGroups not implemented" );
// HashMap<Long,GameGroupInfo> info = gameInfo();
// for ( int ii = 0; ii < info.size(); ++ii ) {
// GameGroupInfo ggi = getInfoForGroup( ii );
// if ( ggi.m_expanded ) {
// view.expandGroup( ii );
// }
// }
}
public long getRowIDFor( int group, int child )
@ -126,11 +147,13 @@ public class GameListAdapter implements ExpandableListAdapter {
public long getRowIDFor( long packedPosition )
{
int childPosition = ExpandableListView.
getPackedPositionChild( packedPosition );
int groupPosition = ExpandableListView.
getPackedPositionGroup( packedPosition );
return getRowIDFor( groupPosition, childPosition );
// int childPosition = ListView.
// getPackedPositionChild( packedPosition );
// int groupPosition = ListView.
// getPackedPositionGroup( packedPosition );
// return getRowIDFor( groupPosition, childPosition );
Assert.fail();
return 0;
}
public long getGroupIDFor( int groupPos )
@ -156,121 +179,202 @@ public class GameListAdapter implements ExpandableListAdapter {
deselectGroups( groupIDs );
}
//////////////////////////////////////////////////////////////////////
// GroupStateListener interface
//////////////////////////////////////////////////////////////////////
public void onGroupExpandedChanged( int groupPosition, boolean expanded )
{
if ( expanded ) {
onGroupExpanded( groupPosition );
} else {
onGroupCollapsed( groupPosition );
}
}
//////////////////////////////////////////////////////////////////////////
// ListAdapter interface
//////////////////////////////////////////////////////////////////////////
public View getView( final int position, View convertView, ViewGroup parent )
{
DbgUtils.logf( "getView(convertView=%H)", convertView );
View result = null;
HashMap<Long,GameGroupInfo> info = gameInfo();
int groupPosition = 0;
int indx = position;
long[] groupPosns = getGroupPositions();
for ( long groupID : groupPosns ) {
GameGroupInfo groupInfo = info.get( groupID );
if ( indx == 0 ) {
int nKids = getChildrenCount( groupPosition );
GameListGroup group =
GameListGroup.makeForPosition( m_context, groupPosition,
groupID, nKids,
groupInfo.m_expanded,
m_cb, this );
if ( !groupInfo.m_expanded ) {
GameGroupInfo ggi = getInfoForGroup( groupPosition );
group.setPct( m_handler, ggi.m_hasTurn, ggi.m_turnLocal,
ggi.m_lastMoveTime );
}
String name = m_context.getString( R.string.group_namef,
groupNames()[groupPosition],
nKids );
group.setText( name );
group.setSelected( m_cb.getSelected( group ) );
result = group;
break;
} else {
int count = groupInfo.m_expanded ? groupInfo.m_count : 0;
// int count = groupInfo.m_count;
// DbgUtils.logf( "group[%d] visible count: %d", groupPosition, count );
if ( indx <= count ) {
long[] rows = DBUtils.getGroupGames( m_context, groupID );
long rowid = rows[indx - 1];
result =
GameListItem.makeForRow( m_context, rowid, m_handler,
groupPosition, m_fieldID, m_cb );
result.setVisibility( groupInfo.m_expanded ?
View.VISIBLE : View.GONE );
break;
}
indx -= 1 + count;
++groupPosition;
}
}
DbgUtils.logf( "GameListAdapter.getView(pos=%d, group=%d)=>%H",
position, groupPosition, result );
return result;
}
@Override
public Object getItem( int position )
{
return getView( position, null, null );
}
//////////////////////////////////////////////////////////////////////////
// ExpandableListAdapter interface
//////////////////////////////////////////////////////////////////////////
public long getCombinedGroupId( long groupId )
{
return groupId;
}
// public long getCombinedGroupId( long groupId )
// {
// return groupId;
// }
public long getCombinedChildId( long groupId, long childId )
{
return groupId << 16 | childId;
}
// public long getCombinedChildId( long groupId, long childId )
// {
// return groupId << 16 | childId;
// }
public boolean isEmpty() { return false; }
// public boolean isEmpty() { return false; }
public void onGroupCollapsed( int groupPosition )
private void onGroupCollapsed( int groupPosition )
{
long groupid = getGroupIDFor( groupPosition );
DBUtils.setGroupExpanded( m_context, groupid, false );
long[] rowids = DBUtils.getGroupGames( m_context, groupid );
deselectGames( rowids );
notifyDataSetChanged();
}
public void onGroupExpanded( int groupPosition )
private void onGroupExpanded( int groupPosition )
{
long groupid = getGroupIDFor( groupPosition );
DBUtils.setGroupExpanded( m_context, groupid, true );
notifyDataSetChanged();
}
public boolean areAllItemsEnabled() { return true; }
// public boolean areAllItemsEnabled() { return true; }
public boolean isChildSelectable( int groupPosition, int childPosition )
{ return true; }
// public boolean isChildSelectable( int groupPosition, int childPosition )
// { return true; }
public View getChildView( int groupPosition, int childPosition,
boolean isLastChild, View convertView,
ViewGroup parent)
{
View result = null;
if ( null != convertView ) {
// DbgUtils.logf( "getChildView gave non-null convertView" );
if ( convertView instanceof GameListItem ) {
GameListItem child = (GameListItem)convertView;
long rowid = getRowIDFor( groupPosition, childPosition );
if ( child.getRowID() == rowid ) {
child.setSelected( m_cb.getSelected( child ) );
result = child;
}
}
}
if ( null == result ) {
result = getChildView( groupPosition, childPosition );
}
return result;
}
// public View getChildView( int groupPosition, int childPosition,
// boolean isLastChild, View convertView,
// ViewGroup parent)
// {
// View result = null;
// if ( null != convertView ) {
// // DbgUtils.logf( "getChildView gave non-null convertView" );
// if ( convertView instanceof GameListItem ) {
// GameListItem child = (GameListItem)convertView;
// long rowid = getRowIDFor( groupPosition, childPosition );
// if ( child.getRowID() == rowid ) {
// child.setSelected( m_cb.getSelected( child ) );
// result = child;
// }
// }
// }
// if ( null == result ) {
// result = getChildView( groupPosition, childPosition );
// }
// return result;
// }
private View getChildView( int groupPosition, int childPosition )
{
long rowid = getRowIDFor( groupPosition, childPosition );
GameListItem result =
GameListItem.makeForRow( m_context, rowid, m_handler,
groupPosition, m_fieldID, m_cb );
result.setSelected( m_cb.getSelected( result ) );
return result;
}
// private View getChildView( int groupPosition, int childPosition )
// {
// long rowid = getRowIDFor( groupPosition, childPosition );
// GameListItem result =
// GameListItem.makeForRow( m_context, rowid, m_handler,
// groupPosition, m_fieldID, m_cb );
// result.setSelected( m_cb.getSelected( result ) );
// return result;
// }
public View getGroupView( int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent )
{
// if ( null != convertView ) {
// DbgUtils.logf( "getGroupView gave non-null convertView" );
// }
long groupID = getGroupIDFor( groupPosition );
GameListGroup view =
GameListGroup.makeForPosition( m_context, groupPosition, groupID,
m_cb );
// public View getGroupView( int groupPosition, boolean isExpanded,
// View convertView, ViewGroup parent )
// {
// // if ( null != convertView ) {
// // DbgUtils.logf( "getGroupView gave non-null convertView" );
// // }
// long groupID = getGroupIDFor( groupPosition );
// GameListGroup view =
// GameListGroup.makeForPosition( m_context, groupPosition, groupID,
// m_cb );
if ( !isExpanded ) {
GameGroupInfo ggi = getInfoForGroup( groupPosition );
view.setPct( m_handler, ggi.m_hasTurn, ggi.m_turnLocal,
ggi.m_lastMoveTime );
}
// if ( !isExpanded ) {
// GameGroupInfo ggi = getInfoForGroup( groupPosition );
// view.setPct( m_handler, ggi.m_hasTurn, ggi.m_turnLocal,
// ggi.m_lastMoveTime );
// }
int nKids = getChildrenCount( groupPosition );
String name = m_context.getString( R.string.group_namef,
groupNames()[groupPosition], nKids );
view.setText( name );
// int nKids = getChildrenCount( groupPosition );
// String name = m_context.getString( R.string.group_namef,
// groupNames()[groupPosition], nKids );
// view.setText( name );
view.setSelected( m_cb.getSelected( view ) );
// view.setSelected( m_cb.getSelected( view ) );
return view;
}
// return view;
// }
public boolean hasStableIds() { return false; }
// public boolean hasStableIds() { return false; }
public long getChildId( int groupPosition, int childPosition )
{
return childPosition;
}
// public long getChildId( int groupPosition, int childPosition )
// {
// return childPosition;
// }
public long getGroupId( int groupPosition )
{
return groupPosition;
}
// public long getGroupId( int groupPosition )
// {
// return groupPosition;
// }
public Object getChild( int groupPosition, int childPosition )
{
return null;
}
// public Object getChild( int groupPosition, int childPosition )
// {
// return null;
// }
public Object getGroup( int groupPosition )
{
return null;
}
// public Object getGroup( int groupPosition )
// {
// return null;
// }
public int getChildrenCount( int groupPosition )
{
@ -283,13 +387,13 @@ public class GameListAdapter implements ExpandableListAdapter {
return rows.length;
}
public int getGroupCount()
protected int getGroupCount()
{
return gameInfo().size();
}
public void registerDataSetObserver( DataSetObserver obs ){}
public void unregisterDataSetObserver( DataSetObserver obs ){}
// public void registerDataSetObserver( DataSetObserver obs ){}
// public void unregisterDataSetObserver( DataSetObserver obs ){}
public void inval( long rowid )
{
@ -474,7 +578,7 @@ public class GameListAdapter implements ExpandableListAdapter {
GameListGroup group = getGroupItemFor( groupPosition );
if ( null != group ) {
GameGroupInfo ggi = getInfoForGroup( groupPosition );
group.setPct( ggi.m_hasTurn, ggi.m_turnLocal, ggi.m_lastMoveTime );
group.setPct( m_handler, ggi.m_hasTurn, ggi.m_turnLocal, ggi.m_lastMoveTime );
}
}

View file

@ -24,27 +24,52 @@ import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.eehouse.android.xw4.DBUtils.GameGroupInfo;
public class GameListGroup extends ExpiringTextView
implements SelectableItem.LongClickHandler
public class GameListGroup extends ExpiringLinearLayout
implements SelectableItem.LongClickHandler,
View.OnClickListener,
View.OnLongClickListener
{
// Find me a home....
interface GroupStateListener {
void onGroupExpandedChanged( int groupPosition, boolean expanded );
}
private int m_groupPosition;
private long m_groupID;
private boolean m_expanded;
private SelectableItem m_cb;
private GroupStateListener m_gcb;
private TextView m_etv;
private boolean m_selected;
private int m_nGames;
private DrawSelDelegate m_dsdel;
private ImageButton m_expandButton;
public static GameListGroup makeForPosition( Context context,
int groupPosition,
long groupID,
SelectableItem cb )
int nGames,
boolean expanded,
SelectableItem cb,
GroupStateListener gcb )
{
GameListGroup result =
(GameListGroup)Utils.inflate( context, R.layout.game_list_group );
result.m_cb = cb;
result.m_gcb = gcb;
result.m_groupPosition = groupPosition;
result.m_groupID = groupID;
result.m_nGames = nGames;
result.m_expanded = expanded;
result.setButton(); // in case onFinishInflate already called
return result;
}
@ -53,6 +78,23 @@ public class GameListGroup extends ExpiringTextView
super( cx, as );
}
@Override
protected void onFinishInflate()
{
super.onFinishInflate();
m_etv = (TextView)findViewById( R.id.game_name );
m_expandButton = (ImageButton)findViewById( R.id.expander );
// click on me OR the button expands/contracts...
setOnClickListener( this );
m_expandButton.setOnClickListener( this );
m_dsdel = new DrawSelDelegate( this );
setOnLongClickListener( this );
setButton();
}
public void setGroupPosition( int groupPosition )
{
m_groupPosition = groupPosition;
@ -76,6 +118,11 @@ public class GameListGroup extends ExpiringTextView
}
}
protected void setText( String text )
{
m_etv.setText( text );
}
// GameListAdapter.ClickHandler interface
public void longClicked()
{
@ -84,8 +131,41 @@ public class GameListGroup extends ExpiringTextView
protected void toggleSelected()
{
super.toggleSelected();
m_selected = !m_selected;
m_dsdel.showSelected( m_selected );
m_cb.itemToggled( this, m_selected );
}
//////////////////////////////////////////////////
// View.OnLongClickListener interface
//////////////////////////////////////////////////
public boolean onLongClick( View view )
{
longClicked();
return true;
}
//////////////////////////////////////////////////
// View.OnClickListener interface
//////////////////////////////////////////////////
public void onClick( View view )
{
if ( 0 < m_nGames ) {
m_expanded = !m_expanded;
m_gcb.onGroupExpandedChanged( m_groupPosition, m_expanded );
setButton();
}
}
private void setButton()
{
if ( null != m_expandButton ) {
m_expandButton.setVisibility( 0 == m_nGames ?
View.GONE : View.VISIBLE );
m_expandButton.setImageResource( m_expanded ?
R.drawable.expander_ic_maximized :
R.drawable.expander_ic_minimized);
}
}
}

View file

@ -66,8 +66,8 @@ public class GameListItem extends LinearLayout
private int m_fieldID;
private int m_loadingCount;
private int m_groupPosition;
private Drawable m_origDrawable;
private boolean m_selected = false;
private DrawSelDelegate m_dsdel;
public GameListItem( Context cx, AttributeSet as )
{
@ -80,6 +80,7 @@ public class GameListItem extends LinearLayout
m_rowid = DBUtils.ROWID_NOTFOUND;
m_lastMoveTime = 0;
m_loadingCount = 0;
m_dsdel = new DrawSelDelegate( this );
setOnClickListener( new View.OnClickListener() {
@Override
@ -332,12 +333,7 @@ public class GameListItem extends LinearLayout
private void toggleSelected()
{
m_selected = !m_selected;
if ( m_selected ) {
m_origDrawable = getBackground();
setBackgroundColor( XWApp.SEL_COLOR );
} else {
setBackgroundDrawable( m_origDrawable );
}
m_dsdel.showSelected( m_selected );
m_cb.itemToggled( this, m_selected );
}

View file

@ -24,7 +24,7 @@ import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.app.ExpandableListActivity;
import android.app.ListActivity;
import android.os.Bundle;
import android.view.Menu;
@ -35,7 +35,7 @@ import org.eehouse.android.xw4.jni.CurGameInfo;
import junit.framework.Assert;
public class GamesListActivity extends ExpandableListActivity {
public class GamesListActivity extends ListActivity {
// private static final String RELAYIDS_EXTRA = "relayids";
private static final String ROWID_EXTRA = "rowid";
@ -49,7 +49,7 @@ public class GamesListActivity extends ExpandableListActivity {
protected Dialog onCreateDialog( int id )
{
Dialog dialog = super.onCreateDialog( id );
if ( null == dialog ) {
if ( null == dialog && null != m_dlgt ) {
dialog = m_dlgt.createDialog( id );
}
return dialog;
@ -67,6 +67,7 @@ public class GamesListActivity extends ExpandableListActivity {
{
super.onCreate( savedInstanceState );
m_dlgt = new GamesListDelegate( this, savedInstanceState );
m_dlgt.init( savedInstanceState );
} // onCreate
// called when we're brought to the front (probably as a result of

View file

@ -124,7 +124,6 @@ public class GamesListDelegate extends DelegateBase
{
super( activity, savedInstanceState );
m_activity = activity;
init( savedInstanceState );
}
protected Dialog createDialog( int id )
@ -348,7 +347,7 @@ public class GamesListDelegate extends DelegateBase
}
}
private void init( Bundle savedInstanceState )
protected void init( Bundle savedInstanceState )
{
CrashTrack.init( m_activity );
@ -357,7 +356,7 @@ public class GamesListDelegate extends DelegateBase
getBundledData( savedInstanceState );
m_activity.setContentView( R.layout.game_list );
ExpandableListView listview = m_activity.getExpandableListView();
ListView listview = m_activity.getListView();
DBUtils.setDBChangeListener( this );
boolean isUpgrade = Utils.firstBootThisVersion( m_activity );
@ -604,7 +603,7 @@ public class GamesListDelegate extends DelegateBase
protected void contentChanged()
{
if ( null != m_adapter ) {
m_adapter.expandGroups( m_activity.getExpandableListView() );
m_adapter.expandGroups( m_activity.getListView() );
}
}
@ -694,7 +693,8 @@ public class GamesListDelegate extends DelegateBase
enable = nothingSelected && XWPrefs.getStudyEnabled( m_activity );
Utils.setItemVisible( menu, R.id.games_menu_study, enable );
enable = 0 < DBUtils.getGamesWithSendsPending( m_activity ).size();
enable = nothingSelected &&
0 < DBUtils.getGamesWithSendsPending( m_activity ).size();
Utils.setItemVisible( menu, R.id.games_menu_resend, enable );
m_menuPrepared = true;
@ -1351,7 +1351,7 @@ public class GamesListDelegate extends DelegateBase
private GameListAdapter makeNewAdapter()
{
ExpandableListView listview = m_activity.getExpandableListView();
ListView listview = m_activity.getListView();
String field = CommonPrefs.getSummaryField( m_activity );
long[] positions = XWPrefs.getGroupPositions( m_activity );
GameListAdapter adapter =

View file

@ -53,19 +53,17 @@ public class NFCUtils {
}
private static interface SafeNFC {
public void register( Activity activity );
public void register( Activity activity, NFCActor actor );
}
private static class SafeNFCImpl implements SafeNFC {
public void register( final Activity activity )
public void register( final Activity activity, final NFCActor actor )
{
Assert.assertTrue( activity instanceof NFCActor );
NfcManager manager =
(NfcManager)activity.getSystemService( Context.NFC_SERVICE );
if ( null != manager ) {
NfcAdapter adapter = manager.getDefaultAdapter();
if ( null != adapter ) {
final NFCActor actor = (NFCActor)activity;
NfcAdapter.CreateNdefMessageCallback cb =
new NfcAdapter.CreateNdefMessageCallback() {
public NdefMessage createNdefMessage( NfcEvent evt )
@ -117,10 +115,10 @@ public class NFCUtils {
return result;
}
public static void register( Activity activity )
public static void register( Activity activity, NFCActor actor )
{
if ( null != s_safeNFC ) {
s_safeNFC.register( activity );
s_safeNFC.register( activity, actor );
}
}

View file

@ -696,6 +696,7 @@ public class RelayService extends XWService
out.writeShort( BuildConstants.CLIENT_VERS_RELAY );
writeVLIString( out, BuildConstants.GIT_REV );
// writeVLIString( out, String.format( "€%s", Build.MODEL) );
writeVLIString( out, Build.MODEL );
writeVLIString( out, Build.VERSION.RELEASE );
@ -1152,9 +1153,10 @@ public class RelayService extends XWService
if ( null == str ) {
str = "";
}
int len = str.length();
byte[] bytes = str.getBytes( "UTF-8" );
int len = bytes.length;
un2vli( len, os );
os.writeBytes( str );
os.write( bytes, 0, len );
}
private void setMaxIntervalSeconds( int maxIntervalSeconds )

View file

@ -24,11 +24,13 @@ import android.app.ListActivity;
import android.widget.ListAdapter;
import android.content.Context;
import android.database.DataSetObserver;
import android.widget.BaseAdapter;
/**
* Let's see if we can implement a few of these methods just once.
*/
public abstract class XWListAdapter implements ListAdapter {
public abstract class XWListAdapter extends BaseAdapter
implements ListAdapter {
private int m_count;
public XWListAdapter( ) {
@ -49,6 +51,6 @@ public abstract class XWListAdapter implements ListAdapter {
public int getViewTypeCount() { return 1; }
public boolean hasStableIds() { return true; }
public boolean isEmpty() { return getCount() == 0; }
public void registerDataSetObserver( DataSetObserver observer ) {}
public void unregisterDataSetObserver( DataSetObserver observer ) {}
}
// public void registerDataSetObserver( DataSetObserver observer ) {}
// public void unregisterDataSetObserver( DataSetObserver observer ) {}
}

View file

@ -22,7 +22,6 @@ package org.eehouse.android.xw4;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageButton;
@ -38,10 +37,10 @@ public class XWListItem extends LinearLayout
private Context m_context;
private Object m_cached;
private DeleteCallback m_delCb;
private Drawable m_origDrawable;
private boolean m_selected = false;
private SelectableItem m_selCb;
private CheckBox m_checkbox;
private DrawSelDelegate m_dsdel;
public interface DeleteCallback {
void deleteCalled( XWListItem item );
@ -50,6 +49,7 @@ public class XWListItem extends LinearLayout
public XWListItem( Context cx, AttributeSet as ) {
super( cx, as );
m_context = cx;
m_dsdel = new DrawSelDelegate( this );
}
@Override
@ -152,12 +152,9 @@ public class XWListItem extends LinearLayout
private void toggleSelected()
{
m_selected = !m_selected;
if ( m_selected ) {
m_origDrawable = getBackground();
setBackgroundColor( XWApp.SEL_COLOR );
} else {
setBackgroundDrawable( m_origDrawable );
}
m_dsdel.showSelected( m_selected );
m_checkbox.setChecked( m_selected );
m_selCb.itemToggled( this, m_selected );

View file

@ -819,7 +819,7 @@ DBMgr::execSql( const char* const query )
PGresult* result = PQexec( getThreadConn(), query );
ok = PGRES_COMMAND_OK == PQresultStatus(result);
if ( !ok ) {
logf( XW_LOGERROR, "%s: PQexec=>%s;%s", __func__,
logf( XW_LOGERROR, "%s(%s): PQexec=>%s;%s", __func__, query,
PQresStatus(PQresultStatus(result)),
PQresultErrorMessage(result) );
clearThreadConn();

View file

@ -327,6 +327,20 @@ vli2un( const uint8_t** bufpp, const uint8_t* end, uint32_t* out )
return success;
}
static void
checkAllAscii( string& str, const char* ifBad )
{
const char* strp = str.c_str();
while ( '\0' != *strp ) {
if ( 0 != (0x80 & *strp) ) {
logf( XW_LOGERROR, "%s: replacing string %s", __func__, str.c_str(), ifBad );
str.assign( ifBad );
break;
}
++strp;
}
}
static bool
getVLIString( const uint8_t** bufpp, const uint8_t* end,
string& out )
@ -1657,6 +1671,9 @@ handle_udp_packet( UdpThreadClosure* utc )
&& getVLIString( &ptr, end, devDesc )
&& getVLIString( &ptr, end, model )
&& getVLIString( &ptr, end, osVers ) ) {
if ( 3 >= clientVers ) {
checkAllAscii( model, "bad model" );
}
registerDevice( relayID, &devID, utc->addr(),
clientVers, devDesc, model, osVers );
}