mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-31 19:57:06 +01:00
Merge branch 'android_branch' into android_groups
Conflicts: xwords4/android/XWords4/res/values/strings.xml xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java
This commit is contained in:
commit
8a58492389
44 changed files with 1333 additions and 828 deletions
|
@ -22,11 +22,11 @@
|
||||||
to come from a domain that you own or have control over. -->
|
to come from a domain that you own or have control over. -->
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="org.eehouse.android.xw4"
|
package="org.eehouse.android.xw4"
|
||||||
android:versionCode="48"
|
android:versionCode="49"
|
||||||
android:versionName="@string/app_version"
|
android:versionName="@string/app_version"
|
||||||
>
|
>
|
||||||
|
|
||||||
<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="7" />
|
<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="8" />
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
@ -134,14 +134,12 @@
|
||||||
/>
|
/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
<!-- <intent-filter> -->
|
<intent-filter>
|
||||||
<!-- <action android:name="android.intent.action.VIEW" /> -->
|
<action android:name="android.intent.action.VIEW" />
|
||||||
<!-- <category android:name="android.intent.category.DEFAULT" /> -->
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<!-- <category android:name="android.intent.category.BROWSABLE" /> -->
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
<!-- <data android:mimeType="*/*" -->
|
<data android:mimeType="@string/invite_mime" />
|
||||||
<!-- android:scheme="content" -->
|
</intent-filter>
|
||||||
<!-- /> -->
|
|
||||||
<!-- </intent-filter> -->
|
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<!-- downloading dicts -->
|
<!-- downloading dicts -->
|
||||||
|
|
|
@ -10,4 +10,4 @@
|
||||||
# Indicates whether an apk should be generated for each density.
|
# Indicates whether an apk should be generated for each density.
|
||||||
split.density=false
|
split.density=false
|
||||||
# Project target.
|
# Project target.
|
||||||
target=android-7
|
target=android-8
|
||||||
|
|
|
@ -3,95 +3,114 @@
|
||||||
|
|
||||||
|
|
||||||
<!-- top-level layout is hozontal, with an image and another layout -->
|
<!-- top-level layout is hozontal, with an image and another layout -->
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<org.eehouse.android.xw4.GameListItem
|
||||||
android:orientation="horizontal"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:longClickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:clickable="true"
|
||||||
|
android:background="@android:drawable/list_selector_background"
|
||||||
|
>
|
||||||
|
|
||||||
|
<TextView android:id="@+id/view_unloaded"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:longClickable="true"
|
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||||
android:focusable="true"
|
android:gravity="center"
|
||||||
android:clickable="true"
|
android:paddingTop="10dp"
|
||||||
android:background="@android:drawable/list_selector_background"
|
android:paddingBottom="10dp"
|
||||||
>
|
android:text="@string/game_list_tmp"
|
||||||
|
/>
|
||||||
|
|
||||||
<ImageView android:id="@+id/msg_marker"
|
<LinearLayout android:id="@+id/view_loaded"
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="fill_parent"
|
|
||||||
android:layout_gravity="center_vertical|center_horizontal"
|
|
||||||
android:layout_weight="0"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- this layout is vertical, holds everything but the status
|
|
||||||
icon[s] (plural later) -->
|
|
||||||
<LinearLayout android:orientation="vertical"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
>
|
|
||||||
|
|
||||||
<!-- This is the game name and expander -->
|
|
||||||
<LinearLayout android:orientation="horizontal"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
>
|
|
||||||
|
|
||||||
<org.eehouse.android.xw4.ExpiringTextView
|
|
||||||
android:id="@+id/game_name"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ImageButton android:id="@+id/expander"
|
|
||||||
android:layout_width="32dp"
|
|
||||||
android:layout_height="32dp"
|
|
||||||
android:src="@drawable/expander_ic_maximized"
|
|
||||||
/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<!-- This is everything below the name (which can be hidden) -->
|
|
||||||
<LinearLayout android:id="@+id/hideable"
|
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:padding="4sp">
|
android:visibility="gone"
|
||||||
|
>
|
||||||
|
|
||||||
<!-- Player list plus connection status -->
|
<ImageView android:id="@+id/msg_marker"
|
||||||
<LinearLayout android:id="@+id/player_list"
|
android:layout_width="wrap_content"
|
||||||
android:orientation="vertical"
|
android:layout_height="fill_parent"
|
||||||
android:layout_width="wrap_content"
|
android:layout_gravity="center_vertical|center_horizontal"
|
||||||
android:layout_height="fill_parent"
|
android:layout_weight="0"
|
||||||
android:layout_weight="1"
|
/>
|
||||||
android:layout_marginRight="4dip"
|
|
||||||
/> <!-- end players column -->
|
|
||||||
|
|
||||||
<!-- holds right column. Could hold more... -->
|
<!-- this layout is vertical, holds everything but the status
|
||||||
<LinearLayout android:orientation="vertical"
|
icon[s] (plural later) -->
|
||||||
android:layout_width="wrap_content"
|
<LinearLayout android:orientation="vertical"
|
||||||
android:layout_height="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
>
|
android:layout_height="wrap_content"
|
||||||
<TextView android:id="@+id/modtime"
|
>
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="right"
|
|
||||||
/>
|
|
||||||
<TextView android:id="@+id/state"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="right"
|
|
||||||
/>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
|
<!-- This is the game name and expander -->
|
||||||
|
<LinearLayout android:orientation="horizontal"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
>
|
||||||
|
|
||||||
|
<org.eehouse.android.xw4.ExpiringTextView
|
||||||
|
android:id="@+id/game_name"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ImageButton android:id="@+id/expander"
|
||||||
|
android:layout_width="32dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:src="@drawable/expander_ic_maximized"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- This is everything below the name (which can be hidden) -->
|
||||||
|
<LinearLayout android:id="@+id/hideable"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="4sp">
|
||||||
|
|
||||||
|
<!-- Player list plus connection status -->
|
||||||
|
<LinearLayout android:id="@+id/player_list"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_marginRight="4dip"
|
||||||
|
/> <!-- end players column -->
|
||||||
|
|
||||||
|
<!-- holds right column. Could hold more... -->
|
||||||
|
<LinearLayout android:orientation="vertical"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
>
|
||||||
|
<TextView android:id="@+id/modtime"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="right"
|
||||||
|
/>
|
||||||
|
<TextView android:id="@+id/state"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="right"
|
||||||
|
/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
<TextView android:id="@+id/role"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical|center_horizontal"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
</org.eehouse.android.xw4.GameListItem>
|
||||||
|
|
||||||
<TextView android:id="@+id/role"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_vertical|center_horizontal"
|
|
||||||
/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
|
|
||||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
|
||||||
android:gravity="center"
|
|
||||||
android:paddingTop="10dp"
|
|
||||||
android:paddingBottom="10dp"
|
|
||||||
android:text="@string/game_list_tmp"
|
|
||||||
/>
|
|
|
@ -5,18 +5,22 @@
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<b>Crosswords 4.4 beta 56 release</b>
|
<b>Crosswords 4.4 beta 57 release</b>
|
||||||
<ul>New with this release
|
|
||||||
<li>Improve invitations: no more redirection through a website, and
|
<h3>New with this release</h3>
|
||||||
confirm before creating duplicate games</li>
|
<ul>
|
||||||
<li>(For sideloading users only) No more browser involvement in
|
<li>Include new game information as an attachment in email invites
|
||||||
updates: app can launch the installer directly to update
|
for use on devices that don't dispatch URLs correctly in received
|
||||||
itself</li>
|
email (e.g. some by HTC) </li>
|
||||||
<li>Remove notifications when their games are deleted</li>
|
<li>Show final scores alert whenever a finished game is opened -- to
|
||||||
|
make it more clear that it's finished</li>
|
||||||
|
<li>Fix flickering in main screen (games list)</li>
|
||||||
|
<li>Add option, off by default, to keep rack tiles square even when
|
||||||
|
the screen is large enough that they can be taller</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<ul>Next up
|
<h3>Next up</h3>
|
||||||
<li>One more idea for improving invitations</li>
|
<ul>
|
||||||
<li>Allow grouping of games in collapsible user-defined categores: "Games with
|
<li>Allow grouping of games in collapsible user-defined categores: "Games with
|
||||||
Kati", "Finished games", etc.</li>
|
Kati", "Finished games", etc.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_version">4.4 beta 56</string>
|
<string name="app_version">4.4 beta 57</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
<!-- prefs keys -->
|
<!-- prefs keys -->
|
||||||
<string name="key_color_tiles">key_color_tiles</string>
|
<string name="key_color_tiles">key_color_tiles</string>
|
||||||
<string name="key_show_arrow">key_show_arrow</string>
|
<string name="key_show_arrow">key_show_arrow</string>
|
||||||
|
<string name="key_square_tiles">key_square_tiles</string>
|
||||||
<string name="key_explain_robot">key_explain_robot</string>
|
<string name="key_explain_robot">key_explain_robot</string>
|
||||||
<string name="key_skip_confirm">key_skip_confirm</string>
|
<string name="key_skip_confirm">key_skip_confirm</string>
|
||||||
<string name="key_sort_tiles">key_sort_tiles</string>
|
<string name="key_sort_tiles">key_sort_tiles</string>
|
||||||
|
|
|
@ -1233,8 +1233,10 @@
|
||||||
encodings for the greater-than and less-than symbols which
|
encodings for the greater-than and less-than symbols which
|
||||||
are not legal in xml strings.)-->
|
are not legal in xml strings.)-->
|
||||||
<string name="invite_htmf">\u003ca href=\"%1$s\"\u003ETap
|
<string name="invite_htmf">\u003ca href=\"%1$s\"\u003ETap
|
||||||
here\u003c/a\u003E (or the full link below) to accept my invitation and
|
here\u003c/a\u003E (or tap the full link below, or, if you already
|
||||||
join this game.
|
have Crosswords installed, open the attachment) to accept my
|
||||||
|
invitation and join this game.
|
||||||
|
|
||||||
\u003cbr \\\u003E
|
\u003cbr \\\u003E
|
||||||
\u003cbr \\\u003E
|
\u003cbr \\\u003E
|
||||||
(full link: %1$s)
|
(full link: %1$s)
|
||||||
|
@ -2154,4 +2156,13 @@
|
||||||
|
|
||||||
<string name="no_move_onegroup">Moving is impossible until there
|
<string name="no_move_onegroup">Moving is impossible until there
|
||||||
is more than one group.</string>
|
is more than one group.</string>
|
||||||
|
|
||||||
|
<!-- Button shown in game over dialog triggering creation of new
|
||||||
|
game with the same players and parameters as the one that
|
||||||
|
just ended. -->
|
||||||
|
<string name="button_rematch">Rematch</string>
|
||||||
|
|
||||||
|
<string name="square_tiles">Square rack tiles</string>
|
||||||
|
<string name="square_tiles_summary">Even if they can be taller</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -132,6 +132,11 @@
|
||||||
android:summary="@string/show_arrow_summary"
|
android:summary="@string/show_arrow_summary"
|
||||||
android:defaultValue="true"
|
android:defaultValue="true"
|
||||||
/>
|
/>
|
||||||
|
<CheckBoxPreference android:key="@string/key_square_tiles"
|
||||||
|
android:title="@string/square_tiles"
|
||||||
|
android:summary="@string/square_tiles_summary"
|
||||||
|
android:defaultValue="false"
|
||||||
|
/>
|
||||||
<CheckBoxPreference android:key="@string/key_keep_screenon"
|
<CheckBoxPreference android:key="@string/key_keep_screenon"
|
||||||
android:title="@string/keep_screenon"
|
android:title="@string/keep_screenon"
|
||||||
android:summary="@string/keep_screenon_summary"
|
android:summary="@string/keep_screenon_summary"
|
||||||
|
|
|
@ -45,6 +45,14 @@ public class BTInviteActivity extends InviteActivity
|
||||||
private boolean m_firstScan;
|
private boolean m_firstScan;
|
||||||
private int m_checkCount;
|
private int m_checkCount;
|
||||||
|
|
||||||
|
public static void launchForResult( Activity activity, int nMissing,
|
||||||
|
int requestCode )
|
||||||
|
{
|
||||||
|
Intent intent = new Intent( activity, BTInviteActivity.class );
|
||||||
|
intent.putExtra( INTENT_KEY_NMISSING, nMissing );
|
||||||
|
activity.startActivityForResult( intent, requestCode );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate( Bundle savedInstanceState )
|
protected void onCreate( Bundle savedInstanceState )
|
||||||
{
|
{
|
||||||
|
@ -57,7 +65,7 @@ public class BTInviteActivity extends InviteActivity
|
||||||
BTService.clearDevices( this, null ); // will return names
|
BTService.clearDevices( this, null ); // will return names
|
||||||
}
|
}
|
||||||
|
|
||||||
// BTService.BTEventListener interface
|
// MultiService.MultiEventListener interface
|
||||||
@Override
|
@Override
|
||||||
public void eventOccurred( MultiService.MultiEvent event, final Object ... args )
|
public void eventOccurred( MultiService.MultiEvent event, final Object ... args )
|
||||||
{
|
{
|
||||||
|
|
|
@ -147,7 +147,7 @@ public class BTService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setListener( MultiService.BTEventListener li )
|
public static void setListener( MultiService.MultiEventListener li )
|
||||||
{
|
{
|
||||||
if ( XWApp.BTSUPPORTED ) {
|
if ( XWApp.BTSUPPORTED ) {
|
||||||
if ( null == s_srcMgr ) {
|
if ( null == s_srcMgr ) {
|
||||||
|
|
|
@ -75,7 +75,7 @@ public class BoardActivity extends XWActivity
|
||||||
private static final int PICK_TILE_REQUESTTRAY_BLK = DLG_OKONLY + 11;
|
private static final int PICK_TILE_REQUESTTRAY_BLK = DLG_OKONLY + 11;
|
||||||
private static final int DLG_USEDICT = DLG_OKONLY + 12;
|
private static final int DLG_USEDICT = DLG_OKONLY + 12;
|
||||||
private static final int DLG_GETDICT = DLG_OKONLY + 13;
|
private static final int DLG_GETDICT = DLG_OKONLY + 13;
|
||||||
|
private static final int GAME_OVER = DLG_OKONLY + 14;
|
||||||
|
|
||||||
private static final int CHAT_REQUEST = 1;
|
private static final int CHAT_REQUEST = 1;
|
||||||
private static final int BT_INVITE_RESULT = 2;
|
private static final int BT_INVITE_RESULT = 2;
|
||||||
|
@ -114,7 +114,7 @@ public class BoardActivity extends XWActivity
|
||||||
|
|
||||||
private BoardView m_view;
|
private BoardView m_view;
|
||||||
private int m_jniGamePtr;
|
private int m_jniGamePtr;
|
||||||
private GameUtils.GameLock m_gameLock;
|
private GameLock m_gameLock;
|
||||||
private CurGameInfo m_gi;
|
private CurGameInfo m_gi;
|
||||||
private CommsTransport m_xport;
|
private CommsTransport m_xport;
|
||||||
private Handler m_handler = null;
|
private Handler m_handler = null;
|
||||||
|
@ -165,6 +165,7 @@ public class BoardActivity extends XWActivity
|
||||||
|
|
||||||
private int m_missing;
|
private int m_missing;
|
||||||
private boolean m_haveInvited = false;
|
private boolean m_haveInvited = false;
|
||||||
|
private boolean m_overNotShown;
|
||||||
|
|
||||||
private static BoardActivity s_this = null;
|
private static BoardActivity s_this = null;
|
||||||
private static Class s_thisLocker = BoardActivity.class;
|
private static Class s_thisLocker = BoardActivity.class;
|
||||||
|
@ -188,6 +189,27 @@ public class BoardActivity extends XWActivity
|
||||||
return delivered;
|
return delivered;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean feedMessages( long rowid, byte[][] msgs )
|
||||||
|
{
|
||||||
|
boolean delivered = false;
|
||||||
|
Assert.assertNotNull( msgs );
|
||||||
|
synchronized( s_thisLocker ) {
|
||||||
|
if ( null != s_this ) {
|
||||||
|
Assert.assertNotNull( s_this.m_gi );
|
||||||
|
Assert.assertNotNull( s_this.m_gameLock );
|
||||||
|
Assert.assertNotNull( s_this.m_jniThread );
|
||||||
|
if ( rowid == s_this.m_rowid ) {
|
||||||
|
delivered = true; // even if no messages!
|
||||||
|
for ( byte[] msg : msgs ) {
|
||||||
|
s_this.m_jniThread.handle( JNICmd.CMD_RECEIVE, msg,
|
||||||
|
null );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return delivered;
|
||||||
|
}
|
||||||
|
|
||||||
private static void setThis( BoardActivity self )
|
private static void setThis( BoardActivity self )
|
||||||
{
|
{
|
||||||
synchronized( s_thisLocker ) {
|
synchronized( s_thisLocker ) {
|
||||||
|
@ -234,6 +256,7 @@ public class BoardActivity extends XWActivity
|
||||||
case DLG_OKONLY:
|
case DLG_OKONLY:
|
||||||
case DLG_BADWORDS:
|
case DLG_BADWORDS:
|
||||||
case DLG_RETRY:
|
case DLG_RETRY:
|
||||||
|
case GAME_OVER:
|
||||||
ab = new AlertDialog.Builder( this )
|
ab = new AlertDialog.Builder( this )
|
||||||
.setTitle( m_dlgTitle )
|
.setTitle( m_dlgTitle )
|
||||||
.setMessage( m_dlgBytes )
|
.setMessage( m_dlgBytes )
|
||||||
|
@ -246,6 +269,14 @@ public class BoardActivity extends XWActivity
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
ab.setNegativeButton( R.string.button_retry, lstnr );
|
ab.setNegativeButton( R.string.button_retry, lstnr );
|
||||||
|
} else if ( XWApp.REMATCH_SUPPORTED && GAME_OVER == id ) {
|
||||||
|
lstnr = new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick( DialogInterface dlg,
|
||||||
|
int whichButton ) {
|
||||||
|
doRematch();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ab.setNegativeButton( R.string.button_rematch, lstnr );
|
||||||
}
|
}
|
||||||
dialog = ab.create();
|
dialog = ab.create();
|
||||||
Utils.setRemoveOnDismiss( this, dialog, id );
|
Utils.setRemoveOnDismiss( this, dialog, id );
|
||||||
|
@ -499,7 +530,9 @@ public class BoardActivity extends XWActivity
|
||||||
|
|
||||||
Intent intent = getIntent();
|
Intent intent = getIntent();
|
||||||
m_rowid = intent.getLongExtra( GameUtils.INTENT_KEY_ROWID, -1 );
|
m_rowid = intent.getLongExtra( GameUtils.INTENT_KEY_ROWID, -1 );
|
||||||
|
DbgUtils.logf( "BoardActivity: opening rowid %d", m_rowid );
|
||||||
m_haveInvited = intent.getBooleanExtra( GameUtils.INVITED, false );
|
m_haveInvited = intent.getBooleanExtra( GameUtils.INVITED, false );
|
||||||
|
m_overNotShown = true;
|
||||||
|
|
||||||
setBackgroundColor();
|
setBackgroundColor();
|
||||||
setKeepScreenOn();
|
setKeepScreenOn();
|
||||||
|
@ -691,8 +724,13 @@ public class BoardActivity extends XWActivity
|
||||||
item.setTitle( R.string.board_menu_game_final );
|
item.setTitle( R.string.board_menu_game_final );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( DeviceRole.SERVER_STANDALONE == m_gi.serverRole ) {
|
||||||
|
Utils.setItemVisible( menu, R.id.board_menu_game_resend, false );
|
||||||
|
Utils.setItemVisible( menu, R.id.gamel_menu_checkmoves, false );
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
} // onPrepareOptionsMenu
|
||||||
|
|
||||||
public boolean onOptionsItemSelected( MenuItem item )
|
public boolean onOptionsItemSelected( MenuItem item )
|
||||||
{
|
{
|
||||||
|
@ -830,12 +868,12 @@ public class BoardActivity extends XWActivity
|
||||||
doSyncMenuitem();
|
doSyncMenuitem();
|
||||||
break;
|
break;
|
||||||
case BT_PICK_ACTION:
|
case BT_PICK_ACTION:
|
||||||
GameUtils.launchBTInviter( this, m_nMissingPlayers,
|
BTInviteActivity.launchForResult( this, m_nMissingPlayers,
|
||||||
BT_INVITE_RESULT );
|
BT_INVITE_RESULT );
|
||||||
break;
|
break;
|
||||||
case SMS_PICK_ACTION:
|
case SMS_PICK_ACTION:
|
||||||
GameUtils.launchSMSInviter( this, m_nMissingPlayers,
|
SMSInviteActivity.launchForResult( this, m_nMissingPlayers,
|
||||||
SMS_INVITE_RESULT );
|
SMS_INVITE_RESULT );
|
||||||
break;
|
break;
|
||||||
case SMS_CONFIG_ACTION:
|
case SMS_CONFIG_ACTION:
|
||||||
Utils.launchSettings( this );
|
Utils.launchSettings( this );
|
||||||
|
@ -907,7 +945,7 @@ public class BoardActivity extends XWActivity
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////
|
//////////////////////////////////////////////////
|
||||||
// BTService.BTEventListener interface
|
// MultiService.MultiEventListener interface
|
||||||
//////////////////////////////////////////////////
|
//////////////////////////////////////////////////
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("fallthrough")
|
@SuppressWarnings("fallthrough")
|
||||||
|
@ -1635,7 +1673,7 @@ public class BoardActivity extends XWActivity
|
||||||
showDictGoneFinish();
|
showDictGoneFinish();
|
||||||
} else {
|
} else {
|
||||||
Assert.assertNull( m_gameLock );
|
Assert.assertNull( m_gameLock );
|
||||||
m_gameLock = new GameUtils.GameLock( m_rowid, true ).lock();
|
m_gameLock = new GameLock( m_rowid, true ).lock();
|
||||||
|
|
||||||
byte[] stream = GameUtils.savedGame( this, m_gameLock );
|
byte[] stream = GameUtils.savedGame( this, m_gameLock );
|
||||||
m_gi = new CurGameInfo( this );
|
m_gi = new CurGameInfo( this );
|
||||||
|
@ -1693,6 +1731,11 @@ public class BoardActivity extends XWActivity
|
||||||
launchLookup( wordsToArray((String)msg.obj),
|
launchLookup( wordsToArray((String)msg.obj),
|
||||||
m_gi.dictLang );
|
m_gi.dictLang );
|
||||||
break;
|
break;
|
||||||
|
case JNIThread.GAME_OVER:
|
||||||
|
m_dlgBytes = (String)msg.obj;
|
||||||
|
m_dlgTitle = msg.arg1;
|
||||||
|
showDialog( GAME_OVER );
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1722,8 +1765,18 @@ public class BoardActivity extends XWActivity
|
||||||
if ( 0 != (GameSummary.MSG_FLAGS_CHAT & flags) ) {
|
if ( 0 != (GameSummary.MSG_FLAGS_CHAT & flags) ) {
|
||||||
startChatActivity();
|
startChatActivity();
|
||||||
}
|
}
|
||||||
if ( 0 != (GameSummary.MSG_FLAGS_GAMEOVER & flags) ) {
|
if ( m_overNotShown ) {
|
||||||
m_jniThread.handle( JNICmd.CMD_POST_OVER );
|
boolean auto = false;
|
||||||
|
if ( 0 != (GameSummary.MSG_FLAGS_GAMEOVER & flags) ) {
|
||||||
|
m_gameOver = true;
|
||||||
|
} else if ( DBUtils.gameOver( this, m_rowid ) ) {
|
||||||
|
m_gameOver = true;
|
||||||
|
auto = true;
|
||||||
|
}
|
||||||
|
if ( m_gameOver ) {
|
||||||
|
m_overNotShown = false;
|
||||||
|
m_jniThread.handle( JNICmd.CMD_POST_OVER, auto );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ( 0 != flags ) {
|
if ( 0 != flags ) {
|
||||||
DBUtils.setMsgFlags( m_rowid, GameSummary.MSG_FLAGS_NONE );
|
DBUtils.setMsgFlags( m_rowid, GameSummary.MSG_FLAGS_NONE );
|
||||||
|
@ -2074,4 +2127,11 @@ public class BoardActivity extends XWActivity
|
||||||
m_passwdEdit = (EditText)m_passwdLyt.findViewById( R.id.edit );
|
m_passwdEdit = (EditText)m_passwdLyt.findViewById( R.id.edit );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void doRematch()
|
||||||
|
{
|
||||||
|
Intent intent = GamesList.makeRematchIntent( this, m_gi, m_rowid );
|
||||||
|
startActivity( intent );
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
} // class BoardActivity
|
} // class BoardActivity
|
||||||
|
|
|
@ -379,8 +379,13 @@ public class BoardView extends View implements DrawCtx, BoardHandler,
|
||||||
heightLeft = cellSize * 3 / 2;
|
heightLeft = cellSize * 3 / 2;
|
||||||
}
|
}
|
||||||
heightLeft /= 3;
|
heightLeft /= 3;
|
||||||
trayHt += heightLeft * 2;
|
|
||||||
scoreHt += heightLeft;
|
scoreHt += heightLeft;
|
||||||
|
|
||||||
|
trayHt += heightLeft * 2;
|
||||||
|
if ( XWPrefs.getSquareTiles( m_context )
|
||||||
|
&& trayHt > (width / 7) ) {
|
||||||
|
trayHt = width / 7;
|
||||||
|
}
|
||||||
heightUsed = trayHt + scoreHt + ((nCells - nToScroll) * cellSize);
|
heightUsed = trayHt + scoreHt + ((nCells - nToScroll) * cellSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ public class DBHelper extends SQLiteOpenHelper {
|
||||||
public static final String INVITEID = "INVITEID";
|
public static final String INVITEID = "INVITEID";
|
||||||
public static final String RELAYID = "RELAYID";
|
public static final String RELAYID = "RELAYID";
|
||||||
public static final String SEED = "SEED";
|
public static final String SEED = "SEED";
|
||||||
public static final String SMSPHONE = "SMSPHONE";
|
public static final String SMSPHONE = "SMSPHONE"; // unused -- so far
|
||||||
public static final String LASTMOVE = "LASTMOVE";
|
public static final String LASTMOVE = "LASTMOVE";
|
||||||
public static final String GROUPID = "GROUPID";
|
public static final String GROUPID = "GROUPID";
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ public class DBHelper extends SQLiteOpenHelper {
|
||||||
,SEED, "INTEGER"
|
,SEED, "INTEGER"
|
||||||
,DICTLANG, "INTEGER"
|
,DICTLANG, "INTEGER"
|
||||||
,DICTLIST, "TEXT"
|
,DICTLIST, "TEXT"
|
||||||
,SMSPHONE, "TEXT"
|
,SMSPHONE, "TEXT" // unused
|
||||||
,SCORES, "TEXT"
|
,SCORES, "TEXT"
|
||||||
,CHAT_HISTORY, "TEXT"
|
,CHAT_HISTORY, "TEXT"
|
||||||
,GAMEID, "INTEGER"
|
,GAMEID, "INTEGER"
|
||||||
|
|
|
@ -60,9 +60,10 @@ public class DBUtils {
|
||||||
|
|
||||||
private static long s_cachedRowID = -1;
|
private static long s_cachedRowID = -1;
|
||||||
private static byte[] s_cachedBytes = null;
|
private static byte[] s_cachedBytes = null;
|
||||||
|
private static long[] s_cachedRowIDs = null;
|
||||||
|
|
||||||
public static interface DBChangeListener {
|
public static interface DBChangeListener {
|
||||||
public void gameSaved( long rowid );
|
public void gameSaved( long rowid, boolean countChanged );
|
||||||
}
|
}
|
||||||
private static HashSet<DBChangeListener> s_listeners =
|
private static HashSet<DBChangeListener> s_listeners =
|
||||||
new HashSet<DBChangeListener>();
|
new HashSet<DBChangeListener>();
|
||||||
|
@ -100,8 +101,7 @@ public class DBUtils {
|
||||||
long maxMillis )
|
long maxMillis )
|
||||||
{
|
{
|
||||||
GameSummary result = null;
|
GameSummary result = null;
|
||||||
GameUtils.GameLock lock =
|
GameLock lock = new GameLock( rowid, false ).lock( maxMillis );
|
||||||
new GameUtils.GameLock( rowid, false ).lock( maxMillis );
|
|
||||||
if ( null != lock ) {
|
if ( null != lock ) {
|
||||||
result = getSummary( context, lock );
|
result = getSummary( context, lock );
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
@ -115,7 +115,7 @@ public class DBUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GameSummary getSummary( Context context,
|
public static GameSummary getSummary( Context context,
|
||||||
GameUtils.GameLock lock )
|
GameLock lock )
|
||||||
{
|
{
|
||||||
initDB( context );
|
initDB( context );
|
||||||
GameSummary summary = null;
|
GameSummary summary = null;
|
||||||
|
@ -129,7 +129,7 @@ public class DBUtils {
|
||||||
DBHelper.TURN, DBHelper.GIFLAGS,
|
DBHelper.TURN, DBHelper.GIFLAGS,
|
||||||
DBHelper.CONTYPE, DBHelper.SERVERROLE,
|
DBHelper.CONTYPE, DBHelper.SERVERROLE,
|
||||||
DBHelper.ROOMNAME, DBHelper.RELAYID,
|
DBHelper.ROOMNAME, DBHelper.RELAYID,
|
||||||
DBHelper.SMSPHONE, DBHelper.SEED,
|
/*DBHelper.SMSPHONE,*/ DBHelper.SEED,
|
||||||
DBHelper.DICTLANG, DBHelper.GAMEID,
|
DBHelper.DICTLANG, DBHelper.GAMEID,
|
||||||
DBHelper.SCORES, DBHelper.HASMSGS,
|
DBHelper.SCORES, DBHelper.HASMSGS,
|
||||||
DBHelper.LASTPLAY_TIME, DBHelper.REMOTEDEVS,
|
DBHelper.LASTPLAY_TIME, DBHelper.REMOTEDEVS,
|
||||||
|
@ -247,13 +247,13 @@ public class DBUtils {
|
||||||
return summary;
|
return summary;
|
||||||
} // getSummary
|
} // getSummary
|
||||||
|
|
||||||
public static void saveSummary( Context context, GameUtils.GameLock lock,
|
public static void saveSummary( Context context, GameLock lock,
|
||||||
GameSummary summary )
|
GameSummary summary )
|
||||||
{
|
{
|
||||||
saveSummary( context, lock, summary, null );
|
saveSummary( context, lock, summary, null );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void saveSummary( Context context, GameUtils.GameLock lock,
|
public static void saveSummary( Context context, GameLock lock,
|
||||||
GameSummary summary, String inviteID )
|
GameSummary summary, String inviteID )
|
||||||
{
|
{
|
||||||
Assert.assertTrue( lock.canWrite() );
|
Assert.assertTrue( lock.canWrite() );
|
||||||
|
@ -314,9 +314,12 @@ public class DBUtils {
|
||||||
long result = db.update( DBHelper.TABLE_NAME_SUM,
|
long result = db.update( DBHelper.TABLE_NAME_SUM,
|
||||||
values, selection, null );
|
values, selection, null );
|
||||||
Assert.assertTrue( result >= 0 );
|
Assert.assertTrue( result >= 0 );
|
||||||
|
if ( result != rowid ) { // new row added
|
||||||
|
clearRowIDsCache();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
notifyListeners( rowid );
|
|
||||||
db.close();
|
db.close();
|
||||||
|
notifyListeners( rowid, false );
|
||||||
}
|
}
|
||||||
} // saveSummary
|
} // saveSummary
|
||||||
|
|
||||||
|
@ -372,7 +375,7 @@ public class DBUtils {
|
||||||
public static void setMsgFlags( long rowid, int flags )
|
public static void setMsgFlags( long rowid, int flags )
|
||||||
{
|
{
|
||||||
setInt( rowid, DBHelper.HASMSGS, flags );
|
setInt( rowid, DBHelper.HASMSGS, flags );
|
||||||
notifyListeners( rowid );
|
notifyListeners( rowid, false );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setExpanded( long rowid, boolean expanded )
|
public static void setExpanded( long rowid, boolean expanded )
|
||||||
|
@ -447,10 +450,8 @@ public class DBUtils {
|
||||||
String selection = DBHelper.RELAYID + "='" + relayID + "'";
|
String selection = DBHelper.RELAYID + "='" + relayID + "'";
|
||||||
Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns,
|
Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns,
|
||||||
selection, null, null, null, null );
|
selection, null, null, null, null );
|
||||||
|
result = new long[cursor.getCount()];
|
||||||
for ( int ii = 0; cursor.moveToNext(); ++ii ) {
|
for ( int ii = 0; cursor.moveToNext(); ++ii ) {
|
||||||
if ( null == result ) {
|
|
||||||
result = new long[cursor.getCount()];
|
|
||||||
}
|
|
||||||
result[ii] = cursor.getLong( cursor.getColumnIndex(ROW_ID) );
|
result[ii] = cursor.getLong( cursor.getColumnIndex(ROW_ID) );
|
||||||
}
|
}
|
||||||
cursor.close();
|
cursor.close();
|
||||||
|
@ -469,11 +470,8 @@ public class DBUtils {
|
||||||
String selection = String.format( DBHelper.GAMEID + "=%d", gameID );
|
String selection = String.format( DBHelper.GAMEID + "=%d", gameID );
|
||||||
Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns,
|
Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns,
|
||||||
selection, null, null, null, null );
|
selection, null, null, null, null );
|
||||||
|
result = new long[cursor.getCount()];
|
||||||
for ( int ii = 0; cursor.moveToNext(); ++ii ) {
|
for ( int ii = 0; cursor.moveToNext(); ++ii ) {
|
||||||
if ( null == result ) {
|
|
||||||
result = new long[cursor.getCount()];
|
|
||||||
}
|
|
||||||
result[ii] = cursor.getLong( cursor.getColumnIndex(ROW_ID) );
|
result[ii] = cursor.getLong( cursor.getColumnIndex(ROW_ID) );
|
||||||
}
|
}
|
||||||
cursor.close();
|
cursor.close();
|
||||||
|
@ -574,7 +572,7 @@ public class DBUtils {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String[] getRelayIDs( Context context, boolean noMsgs )
|
public static String[] getRelayIDs( Context context, long[][] rowIDs )
|
||||||
{
|
{
|
||||||
String[] result = null;
|
String[] result = null;
|
||||||
initDB( context );
|
initDB( context );
|
||||||
|
@ -582,26 +580,31 @@ public class DBUtils {
|
||||||
|
|
||||||
synchronized( s_dbHelper ) {
|
synchronized( s_dbHelper ) {
|
||||||
SQLiteDatabase db = s_dbHelper.getReadableDatabase();
|
SQLiteDatabase db = s_dbHelper.getReadableDatabase();
|
||||||
String[] columns = { DBHelper.RELAYID };
|
String[] columns = { ROW_ID, DBHelper.RELAYID };
|
||||||
String selection = DBHelper.RELAYID + " NOT null";
|
String selection = DBHelper.RELAYID + " NOT null";
|
||||||
if ( noMsgs ) {
|
|
||||||
selection += " AND NOT " + DBHelper.HASMSGS;
|
|
||||||
}
|
|
||||||
|
|
||||||
Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns,
|
Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns,
|
||||||
selection, null, null, null, null );
|
selection, null, null, null, null );
|
||||||
|
int count = cursor.getCount();
|
||||||
|
if ( 0 < count ) {
|
||||||
|
result = new String[count];
|
||||||
|
if ( null != rowIDs ) {
|
||||||
|
rowIDs[0] = new long[count];
|
||||||
|
}
|
||||||
|
|
||||||
while ( cursor.moveToNext() ) {
|
int idIndex = cursor.getColumnIndex(DBHelper.RELAYID);
|
||||||
ids.add( cursor.getString( cursor.
|
int rowIndex = cursor.getColumnIndex(ROW_ID);
|
||||||
getColumnIndex(DBHelper.RELAYID)) );
|
for ( int ii = 0; cursor.moveToNext(); ++ii ) {
|
||||||
|
result[ii] = cursor.getString( idIndex );
|
||||||
|
if ( null != rowIDs ) {
|
||||||
|
rowIDs[0][ii] = cursor.getLong( rowIndex );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cursor.close();
|
cursor.close();
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( 0 < ids.size() ) {
|
|
||||||
result = ids.toArray( new String[ids.size()] );
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -675,9 +678,9 @@ public class DBUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GameUtils.GameLock saveNewGame( Context context, byte[] bytes )
|
public static GameLock saveNewGame( Context context, byte[] bytes )
|
||||||
{
|
{
|
||||||
GameUtils.GameLock lock = null;
|
GameLock lock = null;
|
||||||
|
|
||||||
initDB( context );
|
initDB( context );
|
||||||
synchronized( s_dbHelper ) {
|
synchronized( s_dbHelper ) {
|
||||||
|
@ -695,16 +698,16 @@ public class DBUtils {
|
||||||
long rowid = db.insert( DBHelper.TABLE_NAME_SUM, null, values );
|
long rowid = db.insert( DBHelper.TABLE_NAME_SUM, null, values );
|
||||||
|
|
||||||
setCached( rowid, null ); // force reread
|
setCached( rowid, null ); // force reread
|
||||||
|
clearRowIDsCache();
|
||||||
|
|
||||||
lock = new GameUtils.GameLock( rowid, true ).lock();
|
lock = new GameLock( rowid, true ).lock();
|
||||||
|
notifyListeners( rowid, true );
|
||||||
notifyListeners( rowid );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return lock;
|
return lock;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long saveGame( Context context, GameUtils.GameLock lock,
|
public static long saveGame( Context context, GameLock lock,
|
||||||
byte[] bytes, boolean setCreate )
|
byte[] bytes, boolean setCreate )
|
||||||
{
|
{
|
||||||
Assert.assertTrue( lock.canWrite() );
|
Assert.assertTrue( lock.canWrite() );
|
||||||
|
@ -722,13 +725,13 @@ public class DBUtils {
|
||||||
updateRow( context, DBHelper.TABLE_NAME_SUM, rowid, values );
|
updateRow( context, DBHelper.TABLE_NAME_SUM, rowid, values );
|
||||||
|
|
||||||
setCached( rowid, null ); // force reread
|
setCached( rowid, null ); // force reread
|
||||||
if ( -1 != rowid ) { // Is this possible? PENDING
|
if ( -1 != rowid ) { // Means new game?
|
||||||
notifyListeners( rowid );
|
notifyListeners( rowid, false );
|
||||||
}
|
}
|
||||||
return rowid;
|
return rowid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] loadGame( Context context, GameUtils.GameLock lock )
|
public static byte[] loadGame( Context context, GameLock lock )
|
||||||
{
|
{
|
||||||
long rowid = lock.getRowid();
|
long rowid = lock.getRowid();
|
||||||
Assert.assertTrue( -1 != rowid );
|
Assert.assertTrue( -1 != rowid );
|
||||||
|
@ -756,12 +759,16 @@ public class DBUtils {
|
||||||
|
|
||||||
public static void deleteGame( Context context, long rowid )
|
public static void deleteGame( Context context, long rowid )
|
||||||
{
|
{
|
||||||
GameUtils.GameLock lock = new GameUtils.GameLock( rowid, true ).lock();
|
GameLock lock = new GameLock( rowid, true ).lock( 300 );
|
||||||
deleteGame( context, lock );
|
if ( null != lock ) {
|
||||||
lock.unlock();
|
deleteGame( context, lock );
|
||||||
|
lock.unlock();
|
||||||
|
} else {
|
||||||
|
DbgUtils.logf( "deleteGame: unable to lock rowid %d", rowid );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void deleteGame( Context context, GameUtils.GameLock lock )
|
public static void deleteGame( Context context, GameLock lock )
|
||||||
{
|
{
|
||||||
Assert.assertTrue( lock.canWrite() );
|
Assert.assertTrue( lock.canWrite() );
|
||||||
initDB( context );
|
initDB( context );
|
||||||
|
@ -771,34 +778,46 @@ public class DBUtils {
|
||||||
db.delete( DBHelper.TABLE_NAME_SUM, selection, null );
|
db.delete( DBHelper.TABLE_NAME_SUM, selection, null );
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
notifyListeners( lock.getRowid() );
|
clearRowIDsCache();
|
||||||
|
notifyListeners( lock.getRowid(), true );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long[] gamesList( Context context )
|
public static long[] gamesList( Context context )
|
||||||
{
|
{
|
||||||
long[] result = null;
|
long[] result;
|
||||||
|
synchronized( DBUtils.class ) {
|
||||||
|
if ( null == s_cachedRowIDs ) {
|
||||||
|
initDB( context );
|
||||||
|
synchronized( s_dbHelper ) {
|
||||||
|
SQLiteDatabase db = s_dbHelper.getReadableDatabase();
|
||||||
|
|
||||||
initDB( context );
|
String[] columns = { ROW_ID };
|
||||||
synchronized( s_dbHelper ) {
|
String orderBy = DBHelper.CREATE_TIME + " DESC";
|
||||||
SQLiteDatabase db = s_dbHelper.getReadableDatabase();
|
Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM,
|
||||||
|
columns, null, null, null,
|
||||||
String[] columns = { ROW_ID };
|
null, orderBy );
|
||||||
String orderBy = DBHelper.CREATE_TIME + " DESC";
|
int count = cursor.getCount();
|
||||||
Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns,
|
s_cachedRowIDs = new long[count];
|
||||||
null, null, null, null, orderBy );
|
int index = cursor.getColumnIndex( ROW_ID );
|
||||||
int count = cursor.getCount();
|
for ( int ii = 0; cursor.moveToNext(); ++ii ) {
|
||||||
result = new long[count];
|
s_cachedRowIDs[ii] = cursor.getLong( index );
|
||||||
int index = cursor.getColumnIndex( ROW_ID );
|
}
|
||||||
for ( int ii = 0; cursor.moveToNext(); ++ii ) {
|
cursor.close();
|
||||||
result[ii] = cursor.getLong( index );
|
db.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cursor.close();
|
result = s_cachedRowIDs;
|
||||||
db.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void clearRowIDsCache()
|
||||||
|
{
|
||||||
|
synchronized( DBUtils.class ) {
|
||||||
|
s_cachedRowIDs = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get either the file name or game name, preferring the latter.
|
// Get either the file name or game name, preferring the latter.
|
||||||
public static String getName( Context context, long rowid )
|
public static String getName( Context context, long rowid )
|
||||||
{
|
{
|
||||||
|
@ -1099,6 +1118,7 @@ public class DBUtils {
|
||||||
|
|
||||||
public static void loadDB( Context context )
|
public static void loadDB( Context context )
|
||||||
{
|
{
|
||||||
|
clearRowIDsCache();
|
||||||
copyGameDB( context, false );
|
copyGameDB( context, false );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1381,12 +1401,29 @@ public class DBUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void notifyListeners( long rowid )
|
private static void updateRow( Context context, String table,
|
||||||
|
long rowid, ContentValues values )
|
||||||
|
{
|
||||||
|
initDB( context );
|
||||||
|
synchronized( s_dbHelper ) {
|
||||||
|
SQLiteDatabase db = s_dbHelper.getWritableDatabase();
|
||||||
|
|
||||||
|
String selection = String.format( ROW_ID_FMT, rowid );
|
||||||
|
|
||||||
|
int result = db.update( table, values, selection, null );
|
||||||
|
db.close();
|
||||||
|
if ( 0 == result ) {
|
||||||
|
DbgUtils.logf( "updateRow failed" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void notifyListeners( long rowid, boolean countChanged )
|
||||||
{
|
{
|
||||||
synchronized( s_listeners ) {
|
synchronized( s_listeners ) {
|
||||||
Iterator<DBChangeListener> iter = s_listeners.iterator();
|
Iterator<DBChangeListener> iter = s_listeners.iterator();
|
||||||
while ( iter.hasNext() ) {
|
while ( iter.hasNext() ) {
|
||||||
iter.next().gameSaved( rowid );
|
iter.next().gameSaved( rowid, countChanged );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,20 @@ import org.eehouse.android.xw4.jni.CurGameInfo.DeviceRole;
|
||||||
|
|
||||||
public class DictUtils {
|
public class DictUtils {
|
||||||
|
|
||||||
|
// Standard hack for using APIs from an SDK in code to ship on
|
||||||
|
// older devices that don't support it: prevent class loader from
|
||||||
|
// seeing something it'll barf on by loading it manually
|
||||||
|
private static interface SafeDirGetter {
|
||||||
|
public File getDownloadDir();
|
||||||
|
}
|
||||||
|
private static SafeDirGetter s_dirGetter = null;
|
||||||
|
static {
|
||||||
|
int sdkVersion = Integer.valueOf( android.os.Build.VERSION.SDK );
|
||||||
|
if ( 8 <= sdkVersion ) {
|
||||||
|
s_dirGetter = new DirGetter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// keep in sync with loc_names string-array
|
// keep in sync with loc_names string-array
|
||||||
public enum DictLoc { UNKNOWN, BUILT_IN, INTERNAL, EXTERNAL, DOWNLOAD };
|
public enum DictLoc { UNKNOWN, BUILT_IN, INTERNAL, EXTERNAL, DOWNLOAD };
|
||||||
public static final String INVITED = "invited";
|
public static final String INVITED = "invited";
|
||||||
|
@ -566,22 +580,45 @@ public class DictUtils {
|
||||||
return null != getDownloadDir( context );
|
return null != getDownloadDir( context );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Loop through three ways of getting the directory until one
|
||||||
|
// produces a directory I can write to.
|
||||||
public static File getDownloadDir( Context context )
|
public static File getDownloadDir( Context context )
|
||||||
{
|
{
|
||||||
File result = null;
|
File result = null;
|
||||||
if ( haveWriteableSD() ) {
|
outer:
|
||||||
File file = null;
|
for ( int attempt = 0; attempt < 4; ++attempt ) {
|
||||||
String myPath = XWPrefs.getMyDownloadDir( context );
|
switch ( attempt ) {
|
||||||
if ( null != myPath && 0 < myPath.length() ) {
|
case 0:
|
||||||
file = new File( myPath );
|
String myPath = XWPrefs.getMyDownloadDir( context );
|
||||||
} else {
|
if ( null == myPath || 0 == myPath.length() ) {
|
||||||
file = Environment.getExternalStorageDirectory();
|
continue;
|
||||||
if ( null != file ) {
|
|
||||||
file = new File( file, "download/" );
|
|
||||||
}
|
}
|
||||||
|
result = new File( myPath );
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if ( null == s_dirGetter ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
result = s_dirGetter.getDownloadDir();
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
if ( !haveWriteableSD() ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
result = Environment.getExternalStorageDirectory();
|
||||||
|
if ( 2 == attempt && null != result ) {
|
||||||
|
// the old way...
|
||||||
|
result = new File( result, "download/" );
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if ( null != file && file.exists() && file.isDirectory() ) {
|
|
||||||
result = file;
|
// Exit test for loop
|
||||||
|
if ( null != result ) {
|
||||||
|
if ( result.exists() && result.isDirectory() && result.canWrite() ) {
|
||||||
|
break outer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -596,4 +633,13 @@ public class DictUtils {
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class DirGetter implements SafeDirGetter {
|
||||||
|
public File getDownloadDir()
|
||||||
|
{
|
||||||
|
File path = Environment.
|
||||||
|
getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -242,7 +242,7 @@ public class DlgDelegate {
|
||||||
|
|
||||||
public void doSyncMenuitem()
|
public void doSyncMenuitem()
|
||||||
{
|
{
|
||||||
if ( null == DBUtils.getRelayIDs( m_activity, false ) ) {
|
if ( null == DBUtils.getRelayIDs( m_activity, null ) ) {
|
||||||
showOKOnlyDialog( R.string.no_games_to_refresh );
|
showOKOnlyDialog( R.string.no_games_to_refresh );
|
||||||
} else {
|
} else {
|
||||||
RelayReceiver.RestartTimer( m_activity, true );
|
RelayReceiver.RestartTimer( m_activity, true );
|
||||||
|
|
|
@ -194,12 +194,20 @@ public class ExpiringDelegate {
|
||||||
if ( null == m_runnable ) {
|
if ( null == m_runnable ) {
|
||||||
m_runnable = new Runnable() {
|
m_runnable = new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
|
if ( XWApp.DEBUG_EXP_TIMERS ) {
|
||||||
|
DbgUtils.logf( "ExpiringDelegate: timer fired"
|
||||||
|
+ " for %H", this );
|
||||||
|
}
|
||||||
if ( m_active ) {
|
if ( m_active ) {
|
||||||
figurePct();
|
figurePct();
|
||||||
if ( m_haveTurnLocal ) {
|
if ( m_haveTurnLocal ) {
|
||||||
m_back = null;
|
m_back = null;
|
||||||
setBackground();
|
setBackground();
|
||||||
}
|
}
|
||||||
|
if ( XWApp.DEBUG_EXP_TIMERS ) {
|
||||||
|
DbgUtils.logf( "ExpiringDelegate: invalidating"
|
||||||
|
+ " view %H", m_view );
|
||||||
|
}
|
||||||
m_view.invalidate();
|
m_view.invalidate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,7 +92,7 @@ public class GameConfig extends XWActivity
|
||||||
private boolean m_forResult;
|
private boolean m_forResult;
|
||||||
private CurGameInfo m_gi;
|
private CurGameInfo m_gi;
|
||||||
private CurGameInfo m_giOrig;
|
private CurGameInfo m_giOrig;
|
||||||
private GameUtils.GameLock m_gameLock;
|
private GameLock m_gameLock;
|
||||||
private int m_whichPlayer;
|
private int m_whichPlayer;
|
||||||
// private Spinner m_roleSpinner;
|
// private Spinner m_roleSpinner;
|
||||||
// private Spinner m_connectSpinner;
|
// private Spinner m_connectSpinner;
|
||||||
|
@ -473,7 +473,7 @@ public class GameConfig extends XWActivity
|
||||||
|
|
||||||
// Lock in case we're going to config. We *could* re-get the
|
// Lock in case we're going to config. We *could* re-get the
|
||||||
// lock once the user decides to make changes. PENDING.
|
// lock once the user decides to make changes. PENDING.
|
||||||
m_gameLock = new GameUtils.GameLock( m_rowid, true ).lock();
|
m_gameLock = new GameLock( m_rowid, true ).lock();
|
||||||
int gamePtr = GameUtils.loadMakeGame( this, m_giOrig, m_gameLock );
|
int gamePtr = GameUtils.loadMakeGame( this, m_giOrig, m_gameLock );
|
||||||
if ( 0 == gamePtr ) {
|
if ( 0 == gamePtr ) {
|
||||||
showDictGoneFinish();
|
showDictGoneFinish();
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
|
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
|
||||||
/*
|
/*
|
||||||
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
|
* Copyright 2009-2012 by Eric House (xwords@eehouse.org). All rights
|
||||||
* rights reserved.
|
* reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License as
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
@ -21,8 +21,6 @@ package org.eehouse.android.xw4;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.DataSetObserver;
|
import android.database.DataSetObserver;
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
@ -44,7 +42,6 @@ import java.util.Set;
|
||||||
|
|
||||||
import junit.framework.Assert;
|
import junit.framework.Assert;
|
||||||
|
|
||||||
|
|
||||||
import org.eehouse.android.xw4.jni.*;
|
import org.eehouse.android.xw4.jni.*;
|
||||||
import org.eehouse.android.xw4.jni.CurGameInfo.DeviceRole;
|
import org.eehouse.android.xw4.jni.CurGameInfo.DeviceRole;
|
||||||
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
|
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
|
||||||
|
@ -52,242 +49,35 @@ import org.eehouse.android.xw4.DBUtils.GameGroupInfo;
|
||||||
|
|
||||||
public class GameListAdapter implements ExpandableListAdapter {
|
public class GameListAdapter implements ExpandableListAdapter {
|
||||||
private Context m_context;
|
private Context m_context;
|
||||||
|
private ExpandableListView m_list;
|
||||||
private LayoutInflater m_factory;
|
private LayoutInflater m_factory;
|
||||||
private int m_fieldID;
|
private int m_fieldID;
|
||||||
private Handler m_handler;
|
private Handler m_handler;
|
||||||
private static final boolean s_isFire;
|
|
||||||
private static Random s_random;
|
|
||||||
static {
|
|
||||||
s_isFire = Build.MANUFACTURER.equals( "Amazon" );
|
|
||||||
if ( s_isFire ) {
|
|
||||||
s_random = new Random();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ViewInfo implements View.OnClickListener {
|
|
||||||
private View m_view;
|
|
||||||
private View m_hideable;
|
|
||||||
private ExpiringTextView m_name;
|
|
||||||
private boolean m_expanded, m_haveTurn, m_haveTurnLocal;
|
|
||||||
private long m_rowid;
|
|
||||||
private long m_lastMoveTime;
|
|
||||||
private ImageButton m_expandButton;
|
|
||||||
|
|
||||||
public ViewInfo( View view, long rowid )
|
|
||||||
{
|
|
||||||
m_view = view;
|
|
||||||
m_rowid = rowid;
|
|
||||||
m_lastMoveTime = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ViewInfo( View view, long rowid, boolean expanded,
|
|
||||||
long lastMoveTime, boolean haveTurn,
|
|
||||||
boolean haveTurnLocal ) {
|
|
||||||
this( view, rowid );
|
|
||||||
m_expanded = expanded;
|
|
||||||
m_lastMoveTime = lastMoveTime;
|
|
||||||
m_haveTurn = haveTurn;
|
|
||||||
m_haveTurnLocal = haveTurnLocal;
|
|
||||||
m_hideable = (LinearLayout)view.findViewById( R.id.hideable );
|
|
||||||
m_name = (ExpiringTextView)m_view.findViewById( R.id.game_name );
|
|
||||||
m_expandButton = (ImageButton)view.findViewById( R.id.expander );
|
|
||||||
m_expandButton.setOnClickListener( this );
|
|
||||||
showHide();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showHide()
|
|
||||||
{
|
|
||||||
m_expandButton.setImageResource( m_expanded ?
|
|
||||||
R.drawable.expander_ic_maximized :
|
|
||||||
R.drawable.expander_ic_minimized);
|
|
||||||
m_hideable.setVisibility( m_expanded? View.VISIBLE : View.GONE );
|
|
||||||
|
|
||||||
m_name.setBackgroundColor( android.R.color.transparent );
|
|
||||||
m_name.setPct( m_handler, m_haveTurn && !m_expanded,
|
|
||||||
m_haveTurnLocal, m_lastMoveTime );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onClick( View view ) {
|
|
||||||
m_expanded = !m_expanded;
|
|
||||||
DBUtils.setExpanded( m_rowid, m_expanded );
|
|
||||||
showHide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private HashMap<Long,ViewInfo> m_viewsCache;
|
|
||||||
private DateFormat m_df;
|
|
||||||
private LoadItemCB m_cb;
|
private LoadItemCB m_cb;
|
||||||
|
|
||||||
public interface LoadItemCB {
|
public interface LoadItemCB {
|
||||||
public void itemLoaded( long rowid );
|
public void itemClicked( long rowid, GameSummary summary );
|
||||||
public void itemClicked( long rowid );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class LoadItemTask extends AsyncTask<Void, Void, Void> {
|
public GameListAdapter( Context context, ExpandableListView list,
|
||||||
private long m_rowid;
|
Handler handler, LoadItemCB cb, String fieldName )
|
||||||
private Context m_context;
|
{
|
||||||
// private int m_id;
|
|
||||||
public LoadItemTask( Context context, long rowid/*, int id*/ )
|
|
||||||
{
|
|
||||||
m_context = context;
|
|
||||||
m_rowid = rowid;
|
|
||||||
// m_id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Void doInBackground( Void... unused )
|
|
||||||
{
|
|
||||||
// Without this, on the Fire only the last item in the
|
|
||||||
// list it tappable. Likely my fault, but this seems to
|
|
||||||
// work around it.
|
|
||||||
if ( s_isFire ) {
|
|
||||||
try {
|
|
||||||
int sleepTime = 500 + (s_random.nextInt() % 500);
|
|
||||||
Thread.sleep( sleepTime );
|
|
||||||
} catch ( Exception e ) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
View layout = m_factory.inflate( R.layout.game_list_item, null );
|
|
||||||
boolean hideTitle = false;//CommonPrefs.getHideTitleBar(m_context);
|
|
||||||
GameSummary summary = DBUtils.getSummary( m_context, m_rowid, 1500 );
|
|
||||||
if ( null == summary ) {
|
|
||||||
m_rowid = -1;
|
|
||||||
} else {
|
|
||||||
String state = summary.summarizeState();
|
|
||||||
|
|
||||||
TextView view = (TextView)layout.findViewById( R.id.game_name );
|
|
||||||
if ( hideTitle ) {
|
|
||||||
view.setVisibility( View.GONE );
|
|
||||||
} else {
|
|
||||||
String value = null;
|
|
||||||
switch ( m_fieldID ) {
|
|
||||||
case R.string.game_summary_field_empty:
|
|
||||||
break;
|
|
||||||
case R.string.game_summary_field_language:
|
|
||||||
value =
|
|
||||||
DictLangCache.getLangName( m_context,
|
|
||||||
summary.dictLang );
|
|
||||||
break;
|
|
||||||
case R.string.game_summary_field_opponents:
|
|
||||||
value = summary.playerNames();
|
|
||||||
break;
|
|
||||||
case R.string.game_summary_field_state:
|
|
||||||
value = state;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
String name = GameUtils.getName( m_context, m_rowid );
|
|
||||||
|
|
||||||
if ( null != value ) {
|
|
||||||
value = m_context.getString( R.string.str_game_namef,
|
|
||||||
name, value );
|
|
||||||
} else {
|
|
||||||
value = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
view.setText( value );
|
|
||||||
}
|
|
||||||
|
|
||||||
layout.setOnClickListener( new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick( View v ) {
|
|
||||||
m_cb.itemClicked( m_rowid );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
LinearLayout list =
|
|
||||||
(LinearLayout)layout.findViewById( R.id.player_list );
|
|
||||||
boolean haveATurn = false;
|
|
||||||
boolean haveALocalTurn = false;
|
|
||||||
boolean[] isLocal = new boolean[1];
|
|
||||||
for ( int ii = 0; ii < summary.nPlayers; ++ii ) {
|
|
||||||
ExpiringLinearLayout tmp = (ExpiringLinearLayout)
|
|
||||||
m_factory.inflate( R.layout.player_list_elem, null );
|
|
||||||
view = (TextView)tmp.findViewById( R.id.item_name );
|
|
||||||
view.setText( summary.summarizePlayer( ii ) );
|
|
||||||
view = (TextView)tmp.findViewById( R.id.item_score );
|
|
||||||
view.setText( String.format( " %d", summary.scores[ii] ) );
|
|
||||||
boolean thisHasTurn = summary.isNextToPlay( ii, isLocal );
|
|
||||||
if ( thisHasTurn ) {
|
|
||||||
haveATurn = true;
|
|
||||||
if ( isLocal[0] ) {
|
|
||||||
haveALocalTurn = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tmp.setPct( m_handler, thisHasTurn, isLocal[0],
|
|
||||||
summary.lastMoveTime );
|
|
||||||
list.addView( tmp, ii );
|
|
||||||
}
|
|
||||||
|
|
||||||
view = (TextView)layout.findViewById( R.id.state );
|
|
||||||
view.setText( state );
|
|
||||||
view = (TextView)layout.findViewById( R.id.modtime );
|
|
||||||
long lastMoveTime = summary.lastMoveTime;
|
|
||||||
lastMoveTime *= 1000;
|
|
||||||
view.setText( m_df.format( new Date( lastMoveTime ) ) );
|
|
||||||
|
|
||||||
int iconID;
|
|
||||||
ImageView marker =
|
|
||||||
(ImageView)layout.findViewById( R.id.msg_marker );
|
|
||||||
CommsConnType conType = summary.conType;
|
|
||||||
if ( CommsConnType.COMMS_CONN_RELAY == conType ) {
|
|
||||||
iconID = R.drawable.relaygame;
|
|
||||||
} else if ( CommsConnType.COMMS_CONN_BT == conType ) {
|
|
||||||
iconID = android.R.drawable.stat_sys_data_bluetooth;
|
|
||||||
} else if ( CommsConnType.COMMS_CONN_SMS == conType ) {
|
|
||||||
iconID = android.R.drawable.sym_action_chat;
|
|
||||||
} else {
|
|
||||||
iconID = R.drawable.sologame;
|
|
||||||
}
|
|
||||||
marker.setImageResource( iconID );
|
|
||||||
|
|
||||||
view = (TextView)layout.findViewById( R.id.role );
|
|
||||||
String roleSummary = summary.summarizeRole();
|
|
||||||
if ( null != roleSummary ) {
|
|
||||||
view.setText( roleSummary );
|
|
||||||
} else {
|
|
||||||
view.setVisibility( View.GONE );
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean expanded = DBUtils.getExpanded( m_context, m_rowid );
|
|
||||||
ViewInfo vi = new ViewInfo( layout, m_rowid, expanded,
|
|
||||||
summary.lastMoveTime, haveATurn,
|
|
||||||
haveALocalTurn );
|
|
||||||
|
|
||||||
synchronized( m_viewsCache ) {
|
|
||||||
m_viewsCache.put( m_rowid, vi );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
} // doInBackground
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute( Void unused )
|
|
||||||
{
|
|
||||||
if ( -1 != m_rowid ) {
|
|
||||||
m_cb.itemLoaded( m_rowid );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // class LoadItemTask
|
|
||||||
|
|
||||||
public GameListAdapter( Context context, Handler handler, LoadItemCB cb ) {
|
|
||||||
// super( DBUtils.gamesList(context).length );
|
// super( DBUtils.gamesList(context).length );
|
||||||
m_context = context;
|
m_context = context;
|
||||||
|
m_list = list;
|
||||||
m_handler = handler;
|
m_handler = handler;
|
||||||
m_cb = cb;
|
m_cb = cb;
|
||||||
m_factory = LayoutInflater.from( context );
|
m_factory = LayoutInflater.from( context );
|
||||||
m_df = DateFormat.getDateTimeInstance( DateFormat.SHORT,
|
|
||||||
DateFormat.SHORT );
|
|
||||||
|
|
||||||
m_viewsCache = new HashMap<Long,ViewInfo>();
|
m_fieldID = fieldToID( fieldName );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void inval( long rowid )
|
// public void inval( long rowid )
|
||||||
{
|
// {
|
||||||
synchronized( m_viewsCache ) {
|
// synchronized( m_viewsCache ) {
|
||||||
m_viewsCache.remove( rowid );
|
// m_viewsCache.remove( rowid );
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
public void expandGroups( ExpandableListView view )
|
public void expandGroups( ExpandableListView view )
|
||||||
{
|
{
|
||||||
|
@ -301,26 +91,26 @@ public class GameListAdapter implements ExpandableListAdapter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setField( String field )
|
// public void setField( String field )
|
||||||
{
|
// {
|
||||||
int[] ids = {
|
// int[] ids = {
|
||||||
R.string.game_summary_field_empty
|
// R.string.game_summary_field_empty
|
||||||
,R.string.game_summary_field_language
|
// ,R.string.game_summary_field_language
|
||||||
,R.string.game_summary_field_opponents
|
// ,R.string.game_summary_field_opponents
|
||||||
,R.string.game_summary_field_state
|
// ,R.string.game_summary_field_state
|
||||||
};
|
// };
|
||||||
int result = -1;
|
// int result = -1;
|
||||||
for ( int id : ids ) {
|
// for ( int id : ids ) {
|
||||||
if ( m_context.getString( id ).equals( field ) ) {
|
// if ( m_context.getString( id ).equals( field ) ) {
|
||||||
result = id;
|
// result = id;
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
if ( m_fieldID != result ) {
|
// if ( m_fieldID != result ) {
|
||||||
m_viewsCache.clear();
|
// m_viewsCache.clear();
|
||||||
m_fieldID = result;
|
// m_fieldID = result;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
public long getRowIDFor( int group, int child )
|
public long getRowIDFor( int group, int child )
|
||||||
{
|
{
|
||||||
|
@ -473,39 +263,57 @@ public class GameListAdapter implements ExpandableListAdapter {
|
||||||
public void registerDataSetObserver( DataSetObserver obs ){}
|
public void registerDataSetObserver( DataSetObserver obs ){}
|
||||||
public void unregisterDataSetObserver( DataSetObserver obs ){}
|
public void unregisterDataSetObserver( DataSetObserver obs ){}
|
||||||
|
|
||||||
private View getItem( final long rowid )
|
// private View getItem( final long rowid )
|
||||||
|
// {
|
||||||
|
// View layout;
|
||||||
|
// boolean haveLayout = false;
|
||||||
|
// synchronized( m_viewsCache ) {
|
||||||
|
// ViewInfo vi = m_viewsCache.get( rowid );
|
||||||
|
// haveLayout = null != vi;
|
||||||
|
// if ( haveLayout ) {
|
||||||
|
// layout = vi.m_view;
|
||||||
|
// } else {
|
||||||
|
// layout = m_factory.inflate( R.layout.game_list_tmp, null );
|
||||||
|
// vi = new ViewInfo( layout, rowid );
|
||||||
|
// m_viewsCache.put( rowid, vi );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// @Override
|
||||||
|
// public int getCount() {
|
||||||
|
// return DBUtils.gamesList(m_context).length;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Views. A view depends on a summary, which takes time to load.
|
||||||
|
// // When one needs loading it's done via an async task.
|
||||||
|
// public View getView( int position, View convertView, ViewGroup parent )
|
||||||
|
// {
|
||||||
|
// GameListItem result = (GameListItem)
|
||||||
|
// m_factory.inflate( R.layout.game_list_item, null );
|
||||||
|
// result.init( m_handler, DBUtils.gamesList(m_context)[position],
|
||||||
|
// m_fieldID, m_cb );
|
||||||
|
// return result;
|
||||||
|
// }
|
||||||
|
|
||||||
|
public void inval( long rowid )
|
||||||
{
|
{
|
||||||
View layout;
|
GameListItem child = getItemFor( rowid );
|
||||||
boolean haveLayout = false;
|
if ( null != child && child.getRowID() == rowid ) {
|
||||||
synchronized( m_viewsCache ) {
|
child.forceReload();
|
||||||
ViewInfo vi = m_viewsCache.get( rowid );
|
} else {
|
||||||
haveLayout = null != vi;
|
DbgUtils.logf( "no child for rowid %d", rowid );
|
||||||
if ( haveLayout ) {
|
GameListItem.inval( rowid );
|
||||||
layout = vi.m_view;
|
m_list.invalidate();
|
||||||
} else {
|
|
||||||
layout = m_factory.inflate( R.layout.game_list_tmp, null );
|
|
||||||
vi = new ViewInfo( layout, rowid );
|
|
||||||
m_viewsCache.put( rowid, vi );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ( !haveLayout ) {
|
public void invalName( long rowid )
|
||||||
new LoadItemTask( m_context, rowid/*, ++m_taskCounter*/ ).execute();
|
{
|
||||||
|
GameListItem item = getItemFor( rowid );
|
||||||
|
if ( null != item ) {
|
||||||
|
item.invalName();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// this doesn't work. Rather, it breaks highlighting because
|
|
||||||
// the background, if we don't set it, is a more complicated
|
|
||||||
// object like @android:drawable/list_selector_background. I
|
|
||||||
// tried calling getBackground(), expecting to get a Drawable
|
|
||||||
// I could then clone and modify, but null comes back. So
|
|
||||||
// layout must be inheriting its background from elsewhere or
|
|
||||||
// it gets set later, during layout.
|
|
||||||
// if ( (position%2) == 0 ) {
|
|
||||||
// layout.setBackgroundColor( 0xFF3F3F3F );
|
|
||||||
// }
|
|
||||||
|
|
||||||
return layout;
|
|
||||||
} // getItem
|
|
||||||
|
|
||||||
private long[] getRows( String group )
|
private long[] getRows( String group )
|
||||||
{
|
{
|
||||||
|
@ -538,9 +346,67 @@ public class GameListAdapter implements ExpandableListAdapter {
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
private HashMap<String,GameGroupInfo> gameInfo()
|
public boolean setField( String fieldName )
|
||||||
{
|
{
|
||||||
return DBUtils.getGroups( m_context );
|
boolean changed = false;
|
||||||
|
int newID = fieldToID( fieldName );
|
||||||
|
if ( -1 == newID ) {
|
||||||
|
if ( XWApp.DEBUG ) {
|
||||||
|
DbgUtils.logf( "GameListAdapter.setField(): unable to match"
|
||||||
|
+ " fieldName %s", fieldName );
|
||||||
|
}
|
||||||
|
} else if ( m_fieldID != newID ) {
|
||||||
|
if ( XWApp.DEBUG ) {
|
||||||
|
DbgUtils.logf( "setField: clearing views cache for change"
|
||||||
|
+ " from %d to %d", m_fieldID, newID );
|
||||||
|
}
|
||||||
|
m_fieldID = newID;
|
||||||
|
// return true so caller will do onContentChanged.
|
||||||
|
// There's no other way to signal GameListItem instances
|
||||||
|
// since we don't maintain a list of them.
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private GameListItem getItemFor( long rowid )
|
||||||
|
{
|
||||||
|
GameListItem result = null;
|
||||||
|
int position = positionFor( rowid );
|
||||||
|
if ( 0 <= position ) {
|
||||||
|
result = (GameListItem)m_list.getChildAt( position );
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int fieldToID( String fieldName )
|
||||||
|
{
|
||||||
|
int[] ids = {
|
||||||
|
R.string.game_summary_field_empty
|
||||||
|
,R.string.game_summary_field_language
|
||||||
|
,R.string.game_summary_field_opponents
|
||||||
|
,R.string.game_summary_field_state
|
||||||
|
};
|
||||||
|
int result = -1;
|
||||||
|
for ( int id : ids ) {
|
||||||
|
if ( m_context.getString( id ).equals( fieldName ) ) {
|
||||||
|
result = id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int positionFor( long rowid )
|
||||||
|
{
|
||||||
|
int position = -1;
|
||||||
|
long[] rowids = DBUtils.gamesList( m_context );
|
||||||
|
for ( int ii = 0; ii < rowids.length; ++ii ) {
|
||||||
|
if ( rowids[ii] == rowid ) {
|
||||||
|
position = ii;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return position;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,322 @@
|
||||||
|
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
|
||||||
|
/*
|
||||||
|
* Copyright 2009-2012 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.content.Context;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.os.Handler;
|
||||||
|
// import android.text.TextUtils;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashSet;
|
||||||
|
// import java.util.Iterator;
|
||||||
|
|
||||||
|
import org.eehouse.android.xw4.jni.GameSummary;
|
||||||
|
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
|
||||||
|
|
||||||
|
public class GameListItem extends LinearLayout
|
||||||
|
implements View.OnClickListener {
|
||||||
|
|
||||||
|
private static HashSet<Long> s_invalRows = new HashSet<Long>();
|
||||||
|
|
||||||
|
private Context m_context;
|
||||||
|
private boolean m_loaded;
|
||||||
|
private long m_rowid;
|
||||||
|
private View m_hideable;
|
||||||
|
private ExpiringTextView m_name;
|
||||||
|
private boolean m_expanded, m_haveTurn, m_haveTurnLocal;
|
||||||
|
private long m_lastMoveTime;
|
||||||
|
private ImageButton m_expandButton;
|
||||||
|
private Handler m_handler;
|
||||||
|
private GameSummary m_summary;
|
||||||
|
private GameListAdapter.LoadItemCB m_cb;
|
||||||
|
private int m_fieldID;
|
||||||
|
private int m_loadingCount;
|
||||||
|
|
||||||
|
public GameListItem( Context cx, AttributeSet as )
|
||||||
|
{
|
||||||
|
super( cx, as );
|
||||||
|
m_context = cx;
|
||||||
|
m_loaded = false;
|
||||||
|
m_rowid = DBUtils.ROWID_NOTFOUND;
|
||||||
|
m_lastMoveTime = 0;
|
||||||
|
m_loadingCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init( Handler handler, long rowid, int fieldID,
|
||||||
|
GameListAdapter.LoadItemCB cb )
|
||||||
|
{
|
||||||
|
m_handler = handler;
|
||||||
|
m_rowid = rowid;
|
||||||
|
m_fieldID = fieldID;
|
||||||
|
m_cb = cb;
|
||||||
|
|
||||||
|
forceReload();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void forceReload()
|
||||||
|
{
|
||||||
|
// DbgUtils.logf( "GameListItem.forceReload: rowid=%d", m_rowid );
|
||||||
|
m_summary = null;
|
||||||
|
setLoaded( false );
|
||||||
|
// Apparently it's impossible to reliably cancel an existing
|
||||||
|
// AsyncTask, so let it complete, but drop the results as soon
|
||||||
|
// as we're back on the UI thread.
|
||||||
|
++m_loadingCount;
|
||||||
|
new LoadItemTask().execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void invalName()
|
||||||
|
{
|
||||||
|
setName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDraw( Canvas canvas )
|
||||||
|
{
|
||||||
|
super.onDraw( canvas );
|
||||||
|
if ( DBUtils.ROWID_NOTFOUND != m_rowid ) {
|
||||||
|
synchronized( s_invalRows ) {
|
||||||
|
if ( s_invalRows.contains( m_rowid ) ) {
|
||||||
|
forceReload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void update( boolean expanded, long lastMoveTime, boolean haveTurn,
|
||||||
|
boolean haveTurnLocal )
|
||||||
|
{
|
||||||
|
m_expanded = expanded;
|
||||||
|
m_lastMoveTime = lastMoveTime;
|
||||||
|
m_haveTurn = haveTurn;
|
||||||
|
m_haveTurnLocal = haveTurnLocal;
|
||||||
|
m_hideable = (LinearLayout)findViewById( R.id.hideable );
|
||||||
|
m_name = (ExpiringTextView)findViewById( R.id.game_name );
|
||||||
|
m_expandButton = (ImageButton)findViewById( R.id.expander );
|
||||||
|
m_expandButton.setOnClickListener( this );
|
||||||
|
showHide();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getRowID()
|
||||||
|
{
|
||||||
|
return m_rowid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// View.OnClickListener interface
|
||||||
|
public void onClick( View view ) {
|
||||||
|
m_expanded = !m_expanded;
|
||||||
|
DBUtils.setExpanded( m_rowid, m_expanded );
|
||||||
|
showHide();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setLoaded( boolean loaded )
|
||||||
|
{
|
||||||
|
if ( loaded != m_loaded ) {
|
||||||
|
m_loaded = loaded;
|
||||||
|
// This should be enough to invalidate
|
||||||
|
findViewById( R.id.view_unloaded )
|
||||||
|
.setVisibility( loaded ? View.GONE : View.VISIBLE );
|
||||||
|
findViewById( R.id.view_loaded )
|
||||||
|
.setVisibility( loaded ? View.VISIBLE : View.GONE );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showHide()
|
||||||
|
{
|
||||||
|
m_expandButton.setImageResource( m_expanded ?
|
||||||
|
R.drawable.expander_ic_maximized :
|
||||||
|
R.drawable.expander_ic_minimized);
|
||||||
|
m_hideable.setVisibility( m_expanded? View.VISIBLE : View.GONE );
|
||||||
|
|
||||||
|
m_name.setBackgroundColor( android.R.color.transparent );
|
||||||
|
m_name.setPct( m_handler, m_haveTurn && !m_expanded,
|
||||||
|
m_haveTurnLocal, m_lastMoveTime );
|
||||||
|
}
|
||||||
|
|
||||||
|
private String setName()
|
||||||
|
{
|
||||||
|
String state = null; // hack to avoid calling summarizeState twice
|
||||||
|
if ( null != m_summary ) {
|
||||||
|
state = m_summary.summarizeState();
|
||||||
|
TextView view = (TextView)findViewById( R.id.game_name );
|
||||||
|
String value = null;
|
||||||
|
switch ( m_fieldID ) {
|
||||||
|
case R.string.game_summary_field_empty:
|
||||||
|
break;
|
||||||
|
case R.string.game_summary_field_language:
|
||||||
|
value =
|
||||||
|
DictLangCache.getLangName( m_context,
|
||||||
|
m_summary.dictLang );
|
||||||
|
break;
|
||||||
|
case R.string.game_summary_field_opponents:
|
||||||
|
value = m_summary.playerNames();
|
||||||
|
break;
|
||||||
|
case R.string.game_summary_field_state:
|
||||||
|
value = state;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( null != value ) {
|
||||||
|
String name = GameUtils.getName( m_context, m_rowid );
|
||||||
|
value = m_context.getString( R.string.str_game_namef,
|
||||||
|
name, value );
|
||||||
|
} else {
|
||||||
|
value = GameUtils.getName( m_context, m_rowid );
|
||||||
|
}
|
||||||
|
|
||||||
|
view.setText( value );
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setData( final GameSummary summary )
|
||||||
|
{
|
||||||
|
if ( null != summary ) {
|
||||||
|
TextView view;
|
||||||
|
String state = setName();
|
||||||
|
|
||||||
|
setOnClickListener( new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick( View v ) {
|
||||||
|
m_cb.itemClicked( m_rowid, summary );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
LinearLayout list =
|
||||||
|
(LinearLayout)findViewById( R.id.player_list );
|
||||||
|
list.removeAllViews();
|
||||||
|
boolean haveATurn = false;
|
||||||
|
boolean haveALocalTurn = false;
|
||||||
|
boolean[] isLocal = new boolean[1];
|
||||||
|
for ( int ii = 0; ii < summary.nPlayers; ++ii ) {
|
||||||
|
ExpiringLinearLayout tmp = (ExpiringLinearLayout)
|
||||||
|
Utils.inflate( m_context, R.layout.player_list_elem );
|
||||||
|
view = (TextView)tmp.findViewById( R.id.item_name );
|
||||||
|
view.setText( summary.summarizePlayer( ii ) );
|
||||||
|
view = (TextView)tmp.findViewById( R.id.item_score );
|
||||||
|
view.setText( String.format( " %d", summary.scores[ii] ) );
|
||||||
|
boolean thisHasTurn = summary.isNextToPlay( ii, isLocal );
|
||||||
|
if ( thisHasTurn ) {
|
||||||
|
haveATurn = true;
|
||||||
|
if ( isLocal[0] ) {
|
||||||
|
haveALocalTurn = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tmp.setPct( m_handler, thisHasTurn, isLocal[0],
|
||||||
|
summary.lastMoveTime );
|
||||||
|
list.addView( tmp, ii );
|
||||||
|
}
|
||||||
|
|
||||||
|
view = (TextView)findViewById( R.id.state );
|
||||||
|
view.setText( state );
|
||||||
|
view = (TextView)findViewById( R.id.modtime );
|
||||||
|
long lastMoveTime = summary.lastMoveTime;
|
||||||
|
lastMoveTime *= 1000;
|
||||||
|
|
||||||
|
DateFormat df = DateFormat.getDateTimeInstance( DateFormat.SHORT,
|
||||||
|
DateFormat.SHORT );
|
||||||
|
view.setText( df.format( new Date( lastMoveTime ) ) );
|
||||||
|
|
||||||
|
int iconID;
|
||||||
|
ImageView marker =
|
||||||
|
(ImageView)findViewById( R.id.msg_marker );
|
||||||
|
CommsConnType conType = summary.conType;
|
||||||
|
if ( CommsConnType.COMMS_CONN_RELAY == conType ) {
|
||||||
|
iconID = R.drawable.relaygame;
|
||||||
|
} else if ( CommsConnType.COMMS_CONN_BT == conType ) {
|
||||||
|
iconID = android.R.drawable.stat_sys_data_bluetooth;
|
||||||
|
} else if ( CommsConnType.COMMS_CONN_SMS == conType ) {
|
||||||
|
iconID = android.R.drawable.sym_action_chat;
|
||||||
|
} else {
|
||||||
|
iconID = R.drawable.sologame;
|
||||||
|
}
|
||||||
|
marker.setImageResource( iconID );
|
||||||
|
|
||||||
|
view = (TextView)findViewById( R.id.role );
|
||||||
|
String roleSummary = summary.summarizeRole();
|
||||||
|
if ( null != roleSummary ) {
|
||||||
|
view.setText( roleSummary );
|
||||||
|
} else {
|
||||||
|
view.setVisibility( View.GONE );
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean expanded = DBUtils.getExpanded( m_context, m_rowid );
|
||||||
|
|
||||||
|
update( expanded, summary.lastMoveTime, haveATurn,
|
||||||
|
haveALocalTurn );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LoadItemTask extends AsyncTask<Void, Void, GameSummary> {
|
||||||
|
@Override
|
||||||
|
protected GameSummary doInBackground( Void... unused )
|
||||||
|
{
|
||||||
|
return DBUtils.getSummary( m_context, m_rowid, 150 );
|
||||||
|
} // doInBackground
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute( GameSummary summary )
|
||||||
|
{
|
||||||
|
if ( 0 == --m_loadingCount ) {
|
||||||
|
m_summary = summary;
|
||||||
|
setData( summary );
|
||||||
|
setLoaded( null != m_summary );
|
||||||
|
synchronized( s_invalRows ) {
|
||||||
|
s_invalRows.remove( m_rowid );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// DbgUtils.logf( "LoadItemTask for row %d finished; "
|
||||||
|
// + "inval rows now %s",
|
||||||
|
// m_rowid, invalRowsToString() );
|
||||||
|
}
|
||||||
|
} // class LoadItemTask
|
||||||
|
|
||||||
|
public static void inval( long rowid )
|
||||||
|
{
|
||||||
|
synchronized( s_invalRows ) {
|
||||||
|
s_invalRows.add( rowid );
|
||||||
|
}
|
||||||
|
// DbgUtils.logf( "GameListItem.inval(rowid=%d); inval rows now %s",
|
||||||
|
// rowid, invalRowsToString() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// private static String invalRowsToString()
|
||||||
|
// {
|
||||||
|
// String[] strs;
|
||||||
|
// synchronized( s_invalRows ) {
|
||||||
|
// strs = new String[s_invalRows.size()];
|
||||||
|
// Iterator<Long> iter = s_invalRows.iterator();
|
||||||
|
// for ( int ii = 0; iter.hasNext(); ++ii ) {
|
||||||
|
// strs[ii] = String.format("%d", iter.next() );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return TextUtils.join(",", strs );
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,165 @@
|
||||||
|
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
|
||||||
|
/*
|
||||||
|
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
|
||||||
|
* rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.eehouse.android.xw4;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import junit.framework.Assert;
|
||||||
|
|
||||||
|
// Implements read-locks and write-locks per game. A read lock is
|
||||||
|
// obtainable when other read locks are granted but not when a
|
||||||
|
// write lock is. Write-locks are exclusive.
|
||||||
|
public class GameLock {
|
||||||
|
private long m_rowid;
|
||||||
|
private boolean m_isForWrite;
|
||||||
|
private int m_lockCount;
|
||||||
|
StackTraceElement[] m_lockTrace;
|
||||||
|
|
||||||
|
private static HashMap<Long, GameLock>
|
||||||
|
s_locks = new HashMap<Long,GameLock>();
|
||||||
|
|
||||||
|
public GameLock( long rowid, boolean isForWrite )
|
||||||
|
{
|
||||||
|
m_rowid = rowid;
|
||||||
|
m_isForWrite = isForWrite;
|
||||||
|
m_lockCount = 0;
|
||||||
|
if ( XWApp.DEBUG_LOCKS ) {
|
||||||
|
DbgUtils.logf( "GameLock.GameLock(rowid:%d,isForWrite:%b)=>"
|
||||||
|
+ "this: %H", rowid, isForWrite, this );
|
||||||
|
DbgUtils.printStack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This could be written to allow multiple read locks. Let's
|
||||||
|
// see if not doing that causes problems.
|
||||||
|
public boolean tryLock()
|
||||||
|
{
|
||||||
|
boolean gotIt = false;
|
||||||
|
synchronized( s_locks ) {
|
||||||
|
GameLock owner = s_locks.get( m_rowid );
|
||||||
|
if ( null == owner ) { // unowned
|
||||||
|
Assert.assertTrue( 0 == m_lockCount );
|
||||||
|
s_locks.put( m_rowid, this );
|
||||||
|
++m_lockCount;
|
||||||
|
gotIt = true;
|
||||||
|
|
||||||
|
if ( XWApp.DEBUG_LOCKS ) {
|
||||||
|
StackTraceElement[] trace = Thread.currentThread().
|
||||||
|
getStackTrace();
|
||||||
|
m_lockTrace = new StackTraceElement[trace.length];
|
||||||
|
System.arraycopy( trace, 0, m_lockTrace, 0, trace.length );
|
||||||
|
}
|
||||||
|
} else if ( this == owner && ! m_isForWrite ) {
|
||||||
|
Assert.assertTrue( 0 == m_lockCount );
|
||||||
|
++m_lockCount;
|
||||||
|
gotIt = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return gotIt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait forever (but may assert if too long)
|
||||||
|
public GameLock lock()
|
||||||
|
{
|
||||||
|
return this.lock( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version that's allowed to return null -- if maxMillis > 0
|
||||||
|
public GameLock lock( long maxMillis )
|
||||||
|
{
|
||||||
|
GameLock result = null;
|
||||||
|
final long assertTime = 2000;
|
||||||
|
Assert.assertTrue( maxMillis < assertTime );
|
||||||
|
long sleptTime = 0;
|
||||||
|
|
||||||
|
if ( XWApp.DEBUG_LOCKS ) {
|
||||||
|
DbgUtils.logf( "lock %H (rowid:%d, maxMillis=%d)", this, m_rowid, maxMillis );
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( ; ; ) {
|
||||||
|
if ( tryLock() ) {
|
||||||
|
result = this;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ( XWApp.DEBUG_LOCKS ) {
|
||||||
|
DbgUtils.logf( "GameLock.lock() %H failed; sleeping", this );
|
||||||
|
DbgUtils.printStack();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Thread.sleep( 25 ); // milliseconds
|
||||||
|
sleptTime += 25;
|
||||||
|
} catch( InterruptedException ie ) {
|
||||||
|
DbgUtils.loge( ie );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( XWApp.DEBUG_LOCKS ) {
|
||||||
|
DbgUtils.logf( "GameLock.lock() %H awake; "
|
||||||
|
+ "sleptTime now %d millis", this, sleptTime );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( 0 < maxMillis && sleptTime >= maxMillis ) {
|
||||||
|
break;
|
||||||
|
} else if ( sleptTime >= assertTime ) {
|
||||||
|
if ( XWApp.DEBUG_LOCKS ) {
|
||||||
|
DbgUtils.logf( "lock %H overlocked. lock holding stack:",
|
||||||
|
this );
|
||||||
|
DbgUtils.printStack( m_lockTrace );
|
||||||
|
DbgUtils.logf( "lock %H seeking stack:", this );
|
||||||
|
DbgUtils.printStack();
|
||||||
|
}
|
||||||
|
Assert.fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// DbgUtils.logf( "GameLock.lock(%s) done", m_path );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unlock()
|
||||||
|
{
|
||||||
|
// DbgUtils.logf( "GameLock.unlock(%s)", m_path );
|
||||||
|
synchronized( s_locks ) {
|
||||||
|
Assert.assertTrue( this == s_locks.get(m_rowid) );
|
||||||
|
if ( 1 == m_lockCount ) {
|
||||||
|
s_locks.remove( m_rowid );
|
||||||
|
} else {
|
||||||
|
Assert.assertTrue( !m_isForWrite );
|
||||||
|
}
|
||||||
|
--m_lockCount;
|
||||||
|
|
||||||
|
if ( XWApp.DEBUG_LOCKS ) {
|
||||||
|
DbgUtils.logf( "GameLock.unlock: this: %H (rowid:%d) unlocked",
|
||||||
|
this, m_rowid );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getRowid()
|
||||||
|
{
|
||||||
|
return m_rowid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// used only for asserts
|
||||||
|
public boolean canWrite()
|
||||||
|
{
|
||||||
|
return m_isForWrite && 1 == m_lockCount;
|
||||||
|
}
|
||||||
|
}
|
|
@ -46,134 +46,6 @@ public class GameUtils {
|
||||||
public static final String INTENT_KEY_ROWID = "rowid";
|
public static final String INTENT_KEY_ROWID = "rowid";
|
||||||
public static final String INTENT_FORRESULT_ROWID = "forresult";
|
public static final String INTENT_FORRESULT_ROWID = "forresult";
|
||||||
|
|
||||||
// Implements read-locks and write-locks per game. A read lock is
|
|
||||||
// obtainable when other read locks are granted but not when a
|
|
||||||
// write lock is. Write-locks are exclusive.
|
|
||||||
public static class GameLock {
|
|
||||||
private long m_rowid;
|
|
||||||
private boolean m_isForWrite;
|
|
||||||
private int m_lockCount;
|
|
||||||
StackTraceElement[] m_lockTrace;
|
|
||||||
|
|
||||||
private static HashMap<Long, GameLock>
|
|
||||||
s_locks = new HashMap<Long,GameLock>();
|
|
||||||
|
|
||||||
public GameLock( long rowid, boolean isForWrite )
|
|
||||||
{
|
|
||||||
m_rowid = rowid;
|
|
||||||
m_isForWrite = isForWrite;
|
|
||||||
m_lockCount = 0;
|
|
||||||
if ( XWApp.DEBUG_LOCKS ) {
|
|
||||||
DbgUtils.logf( "GameLock.GameLock(rowid:%d,isForWrite:%b)=>"
|
|
||||||
+ "this: %H", rowid, isForWrite, this );
|
|
||||||
DbgUtils.printStack();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This could be written to allow multiple read locks. Let's
|
|
||||||
// see if not doing that causes problems.
|
|
||||||
public boolean tryLock()
|
|
||||||
{
|
|
||||||
boolean gotIt = false;
|
|
||||||
synchronized( s_locks ) {
|
|
||||||
GameLock owner = s_locks.get( m_rowid );
|
|
||||||
if ( null == owner ) { // unowned
|
|
||||||
Assert.assertTrue( 0 == m_lockCount );
|
|
||||||
s_locks.put( m_rowid, this );
|
|
||||||
++m_lockCount;
|
|
||||||
gotIt = true;
|
|
||||||
|
|
||||||
if ( XWApp.DEBUG_LOCKS ) {
|
|
||||||
StackTraceElement[] trace = Thread.currentThread().
|
|
||||||
getStackTrace();
|
|
||||||
m_lockTrace = new StackTraceElement[trace.length];
|
|
||||||
System.arraycopy( trace, 0, m_lockTrace, 0, trace.length );
|
|
||||||
}
|
|
||||||
} else if ( this == owner && ! m_isForWrite ) {
|
|
||||||
Assert.assertTrue( 0 == m_lockCount );
|
|
||||||
++m_lockCount;
|
|
||||||
gotIt = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return gotIt;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait forever (but may assert if too long)
|
|
||||||
public GameLock lock()
|
|
||||||
{
|
|
||||||
return this.lock( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Version that's allowed to return null -- if maxMillis > 0
|
|
||||||
public GameLock lock( long maxMillis )
|
|
||||||
{
|
|
||||||
GameLock result = null;
|
|
||||||
final long assertTime = 2000;
|
|
||||||
Assert.assertTrue( maxMillis < assertTime );
|
|
||||||
long sleptTime = 0;
|
|
||||||
// DbgUtils.logf( "GameLock.lock(%s)", m_path );
|
|
||||||
// Utils.printStack();
|
|
||||||
for ( ; ; ) {
|
|
||||||
if ( tryLock() ) {
|
|
||||||
result = this;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if ( XWApp.DEBUG_LOCKS ) {
|
|
||||||
DbgUtils.logf( "GameLock.lock() %H failed; sleeping", this );
|
|
||||||
DbgUtils.printStack();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Thread.sleep( 25 ); // milliseconds
|
|
||||||
sleptTime += 25;
|
|
||||||
} catch( InterruptedException ie ) {
|
|
||||||
DbgUtils.loge( ie );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( 0 < maxMillis && sleptTime >= maxMillis ) {
|
|
||||||
break;
|
|
||||||
} else if ( sleptTime >= assertTime ) {
|
|
||||||
if ( XWApp.DEBUG_LOCKS ) {
|
|
||||||
DbgUtils.logf( "lock %H overlocked. lock holding stack:",
|
|
||||||
this );
|
|
||||||
DbgUtils.printStack( m_lockTrace );
|
|
||||||
DbgUtils.logf( "lock %H seeking stack:", this );
|
|
||||||
DbgUtils.printStack();
|
|
||||||
}
|
|
||||||
Assert.fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// DbgUtils.logf( "GameLock.lock(%s) done", m_path );
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void unlock()
|
|
||||||
{
|
|
||||||
// DbgUtils.logf( "GameLock.unlock(%s)", m_path );
|
|
||||||
synchronized( s_locks ) {
|
|
||||||
Assert.assertTrue( this == s_locks.get(m_rowid) );
|
|
||||||
if ( 1 == m_lockCount ) {
|
|
||||||
s_locks.remove( m_rowid );
|
|
||||||
} else {
|
|
||||||
Assert.assertTrue( !m_isForWrite );
|
|
||||||
}
|
|
||||||
--m_lockCount;
|
|
||||||
}
|
|
||||||
// DbgUtils.logf( "GameLock.unlock(%s) done", m_path );
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getRowid()
|
|
||||||
{
|
|
||||||
return m_rowid;
|
|
||||||
}
|
|
||||||
|
|
||||||
// used only for asserts
|
|
||||||
public boolean canWrite()
|
|
||||||
{
|
|
||||||
return m_isForWrite && 1 == m_lockCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Object s_syncObj = new Object();
|
private static Object s_syncObj = new Object();
|
||||||
|
|
||||||
public static byte[] savedGame( Context context, long rowid )
|
public static byte[] savedGame( Context context, long rowid )
|
||||||
|
@ -242,10 +114,16 @@ public class GameUtils {
|
||||||
|
|
||||||
public static void resetGame( Context context, long rowidIn )
|
public static void resetGame( Context context, long rowidIn )
|
||||||
{
|
{
|
||||||
GameLock lock = new GameLock( rowidIn, true ).lock();
|
GameLock lock = new GameLock( rowidIn, true ).lock( 500 );
|
||||||
tellDied( context, lock, true );
|
if ( null != lock ) {
|
||||||
resetGame( context, lock, lock, false );
|
tellDied( context, lock, true );
|
||||||
lock.unlock();
|
resetGame( context, lock, lock, false );
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
|
Utils.cancelNotification( context, (int)rowidIn );
|
||||||
|
} else {
|
||||||
|
DbgUtils.logf( "resetGame: unable to open rowid %d", rowidIn );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static GameSummary summarizeAndClose( Context context,
|
private static GameSummary summarizeAndClose( Context context,
|
||||||
|
@ -298,12 +176,17 @@ public class GameUtils {
|
||||||
|
|
||||||
public static long dupeGame( Context context, long rowidIn )
|
public static long dupeGame( Context context, long rowidIn )
|
||||||
{
|
{
|
||||||
boolean juggle = CommonPrefs.getAutoJuggle( context );
|
long rowid = DBUtils.ROWID_NOTFOUND;
|
||||||
GameLock lockSrc = new GameLock( rowidIn, false ).lock();
|
GameLock lockSrc = new GameLock( rowidIn, false ).lock( 300 );
|
||||||
GameLock lockDest = resetGame( context, lockSrc, null, juggle );
|
if ( null != lockSrc ) {
|
||||||
long rowid = lockDest.getRowid();
|
boolean juggle = CommonPrefs.getAutoJuggle( context );
|
||||||
lockDest.unlock();
|
GameLock lockDest = resetGame( context, lockSrc, null, juggle );
|
||||||
lockSrc.unlock();
|
rowid = lockDest.getRowid();
|
||||||
|
lockDest.unlock();
|
||||||
|
lockSrc.unlock();
|
||||||
|
} else {
|
||||||
|
DbgUtils.logf( "dupeGame: unable to open rowid %d", rowidIn );
|
||||||
|
}
|
||||||
return rowid;
|
return rowid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -525,22 +408,6 @@ public class GameUtils {
|
||||||
nPlayersH, null, gameID, isHost );
|
nPlayersH, null, gameID, isHost );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void launchBTInviter( Activity activity, int nMissing,
|
|
||||||
int requestCode )
|
|
||||||
{
|
|
||||||
Intent intent = new Intent( activity, BTInviteActivity.class );
|
|
||||||
intent.putExtra( BTInviteActivity.INTENT_KEY_NMISSING, nMissing );
|
|
||||||
activity.startActivityForResult( intent, requestCode );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void launchSMSInviter( Activity activity, int nMissing,
|
|
||||||
int requestCode )
|
|
||||||
{
|
|
||||||
Intent intent = new Intent( activity, SMSInviteActivity.class );
|
|
||||||
intent.putExtra( SMSInviteActivity.INTENT_KEY_NMISSING, nMissing );
|
|
||||||
activity.startActivityForResult( intent, requestCode );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void launchInviteActivity( Context context,
|
public static void launchInviteActivity( Context context,
|
||||||
boolean choseEmail,
|
boolean choseEmail,
|
||||||
String room, String inviteID,
|
String room, String inviteID,
|
||||||
|
@ -566,18 +433,20 @@ public class GameUtils {
|
||||||
intent.putExtra( Intent.EXTRA_SUBJECT, subject );
|
intent.putExtra( Intent.EXTRA_SUBJECT, subject );
|
||||||
intent.putExtra( Intent.EXTRA_TEXT, Html.fromHtml(message) );
|
intent.putExtra( Intent.EXTRA_TEXT, Html.fromHtml(message) );
|
||||||
|
|
||||||
|
File attach = null;
|
||||||
File tmpdir = XWApp.ATTACH_SUPPORTED ?
|
File tmpdir = XWApp.ATTACH_SUPPORTED ?
|
||||||
DictUtils.getDownloadDir( context ) : null;
|
DictUtils.getDownloadDir( context ) : null;
|
||||||
if ( null == tmpdir ) { // no attachment
|
if ( null != tmpdir ) { // no attachment
|
||||||
|
attach = makeJsonFor( tmpdir, room, inviteID, lang,
|
||||||
|
dict, nPlayers );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( null == attach ) { // no attachment
|
||||||
intent.setType( "message/rfc822");
|
intent.setType( "message/rfc822");
|
||||||
} else {
|
} else {
|
||||||
intent.setType( context.getString( R.string.invite_mime ) );
|
String mime = context.getString( R.string.invite_mime );
|
||||||
|
intent.setType( mime );
|
||||||
File attach = makeJsonFor( tmpdir, room, inviteID, lang,
|
|
||||||
dict, nPlayers );
|
|
||||||
Uri uri = Uri.fromFile( attach );
|
Uri uri = Uri.fromFile( attach );
|
||||||
DbgUtils.logf( "using file uri for attachment: %s",
|
|
||||||
uri.toString() );
|
|
||||||
intent.putExtra( Intent.EXTRA_STREAM, uri );
|
intent.putExtra( Intent.EXTRA_STREAM, uri );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -684,7 +553,6 @@ public class GameUtils {
|
||||||
boolean invited )
|
boolean invited )
|
||||||
{
|
{
|
||||||
Intent intent = new Intent( activity, BoardActivity.class );
|
Intent intent = new Intent( activity, BoardActivity.class );
|
||||||
intent.setAction( Intent.ACTION_EDIT );
|
|
||||||
intent.putExtra( INTENT_KEY_ROWID, rowid );
|
intent.putExtra( INTENT_KEY_ROWID, rowid );
|
||||||
if ( invited ) {
|
if ( invited ) {
|
||||||
intent.putExtra( INVITED, true );
|
intent.putExtra( INVITED, true );
|
||||||
|
@ -734,40 +602,45 @@ public class GameUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean feedMessages( Context context, long rowid,
|
public static boolean feedMessages( Context context, long rowid,
|
||||||
byte[][] msgs, CommsAddrRec ret,
|
byte[][] msgs, CommsAddrRec ret,
|
||||||
MultiMsgSink sink )
|
MultiMsgSink sink )
|
||||||
{
|
{
|
||||||
boolean draw = false;
|
boolean draw = false;
|
||||||
Assert.assertTrue( -1 != rowid );
|
Assert.assertTrue( -1 != rowid );
|
||||||
GameLock lock = new GameLock( rowid, true );
|
if ( null != msgs ) {
|
||||||
if ( lock.tryLock() ) {
|
// timed lock: If a game is opened by BoardActivity just
|
||||||
CurGameInfo gi = new CurGameInfo( context );
|
// as we're trying to deliver this message to it it'll
|
||||||
FeedUtilsImpl feedImpl = new FeedUtilsImpl( context, rowid );
|
// have the lock and we'll never get it. Better to drop
|
||||||
int gamePtr = loadMakeGame( context, gi, feedImpl, sink, lock );
|
// the message than fire the hung-lock assert. Messages
|
||||||
if ( 0 != gamePtr ) {
|
// belong in local pre-delivery storage anyway.
|
||||||
XwJNI.comms_resendAll( gamePtr, false, false );
|
GameLock lock = new GameLock( rowid, true ).lock( 150 );
|
||||||
|
if ( null != lock ) {
|
||||||
|
CurGameInfo gi = new CurGameInfo( context );
|
||||||
|
FeedUtilsImpl feedImpl = new FeedUtilsImpl( context, rowid );
|
||||||
|
int gamePtr = loadMakeGame( context, gi, feedImpl, sink, lock );
|
||||||
|
if ( 0 != gamePtr ) {
|
||||||
|
XwJNI.comms_resendAll( gamePtr, false, false );
|
||||||
|
|
||||||
if ( null != msgs ) {
|
|
||||||
for ( byte[] msg : msgs ) {
|
for ( byte[] msg : msgs ) {
|
||||||
draw = XwJNI.game_receiveMessage( gamePtr, msg, ret )
|
draw = XwJNI.game_receiveMessage( gamePtr, msg, ret )
|
||||||
|| draw;
|
|| draw;
|
||||||
}
|
}
|
||||||
}
|
XwJNI.comms_ackAny( gamePtr );
|
||||||
XwJNI.comms_ackAny( gamePtr );
|
|
||||||
|
|
||||||
// update gi to reflect changes due to messages
|
// update gi to reflect changes due to messages
|
||||||
XwJNI.game_getGi( gamePtr, gi );
|
XwJNI.game_getGi( gamePtr, gi );
|
||||||
saveGame( context, gamePtr, gi, lock, false );
|
saveGame( context, gamePtr, gi, lock, false );
|
||||||
summarizeAndClose( context, lock, gamePtr, gi, feedImpl );
|
summarizeAndClose( context, lock, gamePtr, gi, feedImpl );
|
||||||
|
|
||||||
int flags = setFromFeedImpl( feedImpl );
|
int flags = setFromFeedImpl( feedImpl );
|
||||||
if ( GameSummary.MSG_FLAGS_NONE != flags ) {
|
if ( GameSummary.MSG_FLAGS_NONE != flags ) {
|
||||||
draw = true;
|
draw = true;
|
||||||
DBUtils.setMsgFlags( rowid, flags );
|
DBUtils.setMsgFlags( rowid, flags );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
lock.unlock();
|
||||||
}
|
}
|
||||||
lock.unlock();
|
|
||||||
}
|
}
|
||||||
return draw;
|
return draw;
|
||||||
} // feedMessages
|
} // feedMessages
|
||||||
|
@ -781,52 +654,45 @@ public class GameUtils {
|
||||||
return feedMessages( context, rowid, msgs, ret, sink );
|
return feedMessages( context, rowid, msgs, ret, sink );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Current assumption: this is the relay case where return address
|
|
||||||
// can be null.
|
|
||||||
public static boolean feedMessages( Context context, String relayID,
|
|
||||||
byte[][] msgs, MultiMsgSink sink )
|
|
||||||
{
|
|
||||||
boolean draw = false;
|
|
||||||
long[] rowids = DBUtils.getRowIDsFor( context, relayID );
|
|
||||||
if ( null != rowids ) {
|
|
||||||
for ( long rowid : rowids ) {
|
|
||||||
draw = feedMessages( context, rowid, msgs, null, sink ) || draw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return draw;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This *must* involve a reset if the language is changing!!!
|
// This *must* involve a reset if the language is changing!!!
|
||||||
// Which isn't possible right now, so make sure the old and new
|
// Which isn't possible right now, so make sure the old and new
|
||||||
// dict have the same langauge code.
|
// dict have the same langauge code.
|
||||||
public static void replaceDicts( Context context, long rowid,
|
public static boolean replaceDicts( Context context, long rowid,
|
||||||
String oldDict, String newDict )
|
String oldDict, String newDict )
|
||||||
{
|
{
|
||||||
GameLock lock = new GameLock( rowid, true ).lock();
|
GameLock lock = new GameLock( rowid, true ).lock(300);
|
||||||
byte[] stream = savedGame( context, lock );
|
boolean success = null != lock;
|
||||||
CurGameInfo gi = new CurGameInfo( context );
|
if ( success ) {
|
||||||
XwJNI.gi_from_stream( gi, stream );
|
byte[] stream = savedGame( context, lock );
|
||||||
|
CurGameInfo gi = new CurGameInfo( context );
|
||||||
|
XwJNI.gi_from_stream( gi, stream );
|
||||||
|
|
||||||
// first time required so dictNames() will work
|
// first time required so dictNames() will work
|
||||||
gi.replaceDicts( newDict );
|
gi.replaceDicts( newDict );
|
||||||
|
|
||||||
String[] dictNames = gi.dictNames();
|
String[] dictNames = gi.dictNames();
|
||||||
DictUtils.DictPairs pairs = DictUtils.openDicts( context, dictNames );
|
DictUtils.DictPairs pairs = DictUtils.openDicts( context,
|
||||||
|
dictNames );
|
||||||
|
|
||||||
int gamePtr = XwJNI.initJNI();
|
int gamePtr = XwJNI.initJNI();
|
||||||
XwJNI.game_makeFromStream( gamePtr, stream, gi, dictNames,
|
XwJNI.game_makeFromStream( gamePtr, stream, gi, dictNames,
|
||||||
pairs.m_bytes, pairs.m_paths,
|
pairs.m_bytes, pairs.m_paths,
|
||||||
gi.langName(), JNIUtilsImpl.get(context),
|
gi.langName(),
|
||||||
CommonPrefs.get( context ) );
|
JNIUtilsImpl.get(context),
|
||||||
// second time required as game_makeFromStream can overwrite
|
CommonPrefs.get( context ) );
|
||||||
gi.replaceDicts( newDict );
|
// second time required as game_makeFromStream can overwrite
|
||||||
|
gi.replaceDicts( newDict );
|
||||||
|
|
||||||
saveGame( context, gamePtr, gi, lock, false );
|
saveGame( context, gamePtr, gi, lock, false );
|
||||||
|
|
||||||
summarizeAndClose( context, lock, gamePtr, gi );
|
summarizeAndClose( context, lock, gamePtr, gi );
|
||||||
|
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
}
|
} else {
|
||||||
|
DbgUtils.logf( "replaceDicts: unable to open rowid %d", rowid );
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
} // replaceDicts
|
||||||
|
|
||||||
public static void applyChanges( Context context, CurGameInfo gi,
|
public static void applyChanges( Context context, CurGameInfo gi,
|
||||||
CommsAddrRec car, GameLock lock,
|
CommsAddrRec car, GameLock lock,
|
||||||
|
@ -953,7 +819,7 @@ public class GameUtils {
|
||||||
byte[] data = json.toString().getBytes();
|
byte[] data = json.toString().getBytes();
|
||||||
|
|
||||||
File file = new File( dir,
|
File file = new File( dir,
|
||||||
String.format("invite_%s.json", room ) );
|
String.format("invite_%s", room ) );
|
||||||
FileOutputStream fos = new FileOutputStream( file );
|
FileOutputStream fos = new FileOutputStream( file );
|
||||||
fos.write( data, 0, data.length );
|
fos.write( data, 0, data.length );
|
||||||
fos.close();
|
fos.close();
|
||||||
|
|
|
@ -75,6 +75,7 @@ public class GamesList extends XWExpandableListActivity
|
||||||
|
|
||||||
private static final String RELAYIDS_EXTRA = "relayids";
|
private static final String RELAYIDS_EXTRA = "relayids";
|
||||||
private static final String GAMEID_EXTRA = "gameid";
|
private static final String GAMEID_EXTRA = "gameid";
|
||||||
|
private static final String REMATCH_ROWID_EXTRA = "rowid";
|
||||||
|
|
||||||
private static final int NEW_NET_GAME_ACTION = 1;
|
private static final int NEW_NET_GAME_ACTION = 1;
|
||||||
private static final int RESET_GAME_ACTION = 2;
|
private static final int RESET_GAME_ACTION = 2;
|
||||||
|
@ -102,7 +103,6 @@ public class GamesList extends XWExpandableListActivity
|
||||||
private String m_nameField;
|
private String m_nameField;
|
||||||
private NetLaunchInfo m_netLaunchInfo;
|
private NetLaunchInfo m_netLaunchInfo;
|
||||||
private GameNamer m_namer;
|
private GameNamer m_namer;
|
||||||
// private String m_smsPhone;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Dialog onCreateDialog( int id )
|
protected Dialog onCreateDialog( int id )
|
||||||
|
@ -177,11 +177,12 @@ public class GamesList extends XWExpandableListActivity
|
||||||
getCheckedItemPosition();
|
getCheckedItemPosition();
|
||||||
String dict = m_sameLangDicts[pos];
|
String dict = m_sameLangDicts[pos];
|
||||||
dict = DictLangCache.stripCount( dict );
|
dict = DictLangCache.stripCount( dict );
|
||||||
GameUtils.replaceDicts( GamesList.this,
|
if ( GameUtils.replaceDicts( GamesList.this,
|
||||||
m_missingDictRowId,
|
m_missingDictRowId,
|
||||||
m_missingDictName,
|
m_missingDictName,
|
||||||
dict );
|
dict ) ) {
|
||||||
launchGameIf();
|
launchGameIf();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
dialog = new AlertDialog.Builder( this )
|
dialog = new AlertDialog.Builder( this )
|
||||||
|
@ -202,8 +203,7 @@ public class GamesList extends XWExpandableListActivity
|
||||||
public void onClick( DialogInterface dlg, int item ) {
|
public void onClick( DialogInterface dlg, int item ) {
|
||||||
String name = m_namer.getName();
|
String name = m_namer.getName();
|
||||||
DBUtils.setName( GamesList.this, m_rowid, name );
|
DBUtils.setName( GamesList.this, m_rowid, name );
|
||||||
m_adapter.inval( m_rowid );
|
m_adapter.invalName( m_rowid );
|
||||||
onContentChanged();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
dialog = buildNamerDlg( GameUtils.getName( this, m_rowid ),
|
dialog = buildNamerDlg( GameUtils.getName( this, m_rowid ),
|
||||||
|
@ -346,7 +346,9 @@ public class GamesList extends XWExpandableListActivity
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
m_adapter = new GameListAdapter( this, new Handler(), this );
|
String field = CommonPrefs.getSummaryField( this );
|
||||||
|
m_adapter = new GameListAdapter( this, getListView(), new Handler(),
|
||||||
|
this, field );
|
||||||
setListAdapter( m_adapter );
|
setListAdapter( m_adapter );
|
||||||
|
|
||||||
NetUtils.informOfDeaths( this );
|
NetUtils.informOfDeaths( this );
|
||||||
|
@ -355,6 +357,7 @@ public class GamesList extends XWExpandableListActivity
|
||||||
startFirstHasDict( intent );
|
startFirstHasDict( intent );
|
||||||
startNewNetGame( intent );
|
startNewNetGame( intent );
|
||||||
startHasGameID( intent );
|
startHasGameID( intent );
|
||||||
|
startHasRowID( intent );
|
||||||
askDefaultNameIf();
|
askDefaultNameIf();
|
||||||
} // onCreate
|
} // onCreate
|
||||||
|
|
||||||
|
@ -369,6 +372,7 @@ public class GamesList extends XWExpandableListActivity
|
||||||
startFirstHasDict( intent );
|
startFirstHasDict( intent );
|
||||||
startNewNetGame( intent );
|
startNewNetGame( intent );
|
||||||
startHasGameID( intent );
|
startHasGameID( intent );
|
||||||
|
startHasRowID( intent );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -444,28 +448,25 @@ public class GamesList extends XWExpandableListActivity
|
||||||
}
|
}
|
||||||
|
|
||||||
// DBUtils.DBChangeListener interface
|
// DBUtils.DBChangeListener interface
|
||||||
public void gameSaved( final long rowid )
|
public void gameSaved( final long rowid, final boolean countChanged )
|
||||||
{
|
{
|
||||||
post( new Runnable() {
|
post( new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
m_adapter.inval( rowid );
|
if ( countChanged ) {
|
||||||
onContentChanged();
|
onContentChanged();
|
||||||
|
} else {
|
||||||
|
m_adapter.inval( rowid );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
// GameListAdapter.LoadItemCB interface
|
// GameListAdapter.LoadItemCB interface
|
||||||
public void itemLoaded( long rowid )
|
public void itemClicked( long rowid, GameSummary summary )
|
||||||
{
|
|
||||||
onContentChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void itemClicked( long rowid )
|
|
||||||
{
|
{
|
||||||
// We need a way to let the user get back to the basic-config
|
// We need a way to let the user get back to the basic-config
|
||||||
// dialog in case it was dismissed. That way it to check for
|
// dialog in case it was dismissed. That way it to check for
|
||||||
// an empty room name.
|
// an empty room name.
|
||||||
GameSummary summary = DBUtils.getSummary( this, rowid );
|
|
||||||
if ( summary.conType == CommsAddrRec.CommsConnType.COMMS_CONN_RELAY
|
if ( summary.conType == CommsAddrRec.CommsConnType.COMMS_CONN_RELAY
|
||||||
&& summary.roomName.length() == 0 ) {
|
&& summary.roomName.length() == 0 ) {
|
||||||
// If it's unconfigured and of the type RelayGameActivity
|
// If it's unconfigured and of the type RelayGameActivity
|
||||||
|
@ -480,12 +481,12 @@ public class GamesList extends XWExpandableListActivity
|
||||||
GameUtils.doConfig( this, rowid, clazz );
|
GameUtils.doConfig( this, rowid, clazz );
|
||||||
} else {
|
} else {
|
||||||
if ( checkWarnNoDict( rowid ) ) {
|
if ( checkWarnNoDict( rowid ) ) {
|
||||||
GameUtils.launchGame( this, rowid );
|
launchGame( rowid );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// BTService.BTEventListener interface
|
// BTService.MultiEventListener interface
|
||||||
@Override
|
@Override
|
||||||
public void eventOccurred( MultiService.MultiEvent event,
|
public void eventOccurred( MultiService.MultiEvent event,
|
||||||
final Object ... args )
|
final Object ... args )
|
||||||
|
@ -518,6 +519,7 @@ public class GamesList extends XWExpandableListActivity
|
||||||
break;
|
break;
|
||||||
case RESET_GAME_ACTION:
|
case RESET_GAME_ACTION:
|
||||||
GameUtils.resetGame( this, m_rowid );
|
GameUtils.resetGame( this, m_rowid );
|
||||||
|
onContentChanged(); // required because position may change
|
||||||
break;
|
break;
|
||||||
case DELETE_GAME_ACTION:
|
case DELETE_GAME_ACTION:
|
||||||
GameUtils.deleteGame( this, m_rowid, true );
|
GameUtils.deleteGame( this, m_rowid, true );
|
||||||
|
@ -526,7 +528,6 @@ public class GamesList extends XWExpandableListActivity
|
||||||
long[] games = DBUtils.gamesList( this );
|
long[] games = DBUtils.gamesList( this );
|
||||||
for ( int ii = games.length - 1; ii >= 0; --ii ) {
|
for ( int ii = games.length - 1; ii >= 0; --ii ) {
|
||||||
GameUtils.deleteGame( this, games[ii], ii == 0 );
|
GameUtils.deleteGame( this, games[ii], ii == 0 );
|
||||||
m_adapter.inval( games[ii] );
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SYNC_MENU_ACTION:
|
case SYNC_MENU_ACTION:
|
||||||
|
@ -759,8 +760,7 @@ public class GamesList extends XWExpandableListActivity
|
||||||
showOKOnlyDialog( R.string.no_copy_network );
|
showOKOnlyDialog( R.string.no_copy_network );
|
||||||
} else {
|
} else {
|
||||||
byte[] stream = GameUtils.savedGame( this, m_rowid );
|
byte[] stream = GameUtils.savedGame( this, m_rowid );
|
||||||
GameUtils.GameLock lock =
|
GameLock lock = GameUtils.saveNewGame( this, stream );
|
||||||
GameUtils.saveNewGame( this, stream );
|
|
||||||
DBUtils.saveSummary( this, lock, summary );
|
DBUtils.saveSummary( this, lock, summary );
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
}
|
}
|
||||||
|
@ -859,9 +859,12 @@ public class GamesList extends XWExpandableListActivity
|
||||||
} else if ( null != m_missingDictName ) {
|
} else if ( null != m_missingDictName ) {
|
||||||
showDialog( WARN_NODICT_SUBST );
|
showDialog( WARN_NODICT_SUBST );
|
||||||
} else {
|
} else {
|
||||||
String dict = DictLangCache.getHaveLang( this, m_missingDictLang)[0];
|
String dict =
|
||||||
GameUtils.replaceDicts( this, m_missingDictRowId, null, dict );
|
DictLangCache.getHaveLang( this, m_missingDictLang)[0];
|
||||||
launchGameIf();
|
if ( GameUtils.replaceDicts( this, m_missingDictRowId,
|
||||||
|
null, dict ) ) {
|
||||||
|
launchGameIf();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return hasDicts;
|
return hasDicts;
|
||||||
|
@ -878,7 +881,6 @@ public class GamesList extends XWExpandableListActivity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onContentChanged();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -893,7 +895,7 @@ public class GamesList extends XWExpandableListActivity
|
||||||
if ( null != rowids ) {
|
if ( null != rowids ) {
|
||||||
for ( long rowid : rowids ) {
|
for ( long rowid : rowids ) {
|
||||||
if ( GameUtils.gameDictsHere( this, rowid ) ) {
|
if ( GameUtils.gameDictsHere( this, rowid ) ) {
|
||||||
GameUtils.launchGame( this, rowid );
|
launchGame( rowid );
|
||||||
break outer;
|
break outer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -951,7 +953,7 @@ public class GamesList extends XWExpandableListActivity
|
||||||
{
|
{
|
||||||
long[] rowids = DBUtils.getRowIDsFor( this, gameID );
|
long[] rowids = DBUtils.getRowIDsFor( this, gameID );
|
||||||
if ( null != rowids && 0 < rowids.length ) {
|
if ( null != rowids && 0 < rowids.length ) {
|
||||||
GameUtils.launchGame( this, rowids[0] );
|
launchGame( rowids[0] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -963,6 +965,16 @@ public class GamesList extends XWExpandableListActivity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void startHasRowID( Intent intent )
|
||||||
|
{
|
||||||
|
long rowid = intent.getLongExtra( REMATCH_ROWID_EXTRA, -1 );
|
||||||
|
if ( -1 != rowid ) {
|
||||||
|
// this will juggle if the preference is set
|
||||||
|
long newid = GameUtils.dupeGame( this, rowid );
|
||||||
|
launchGame( newid );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void askDefaultNameIf()
|
private void askDefaultNameIf()
|
||||||
{
|
{
|
||||||
if ( null == CommonPrefs.getDefaultPlayerName( this, 0, false ) ) {
|
if ( null == CommonPrefs.getDefaultPlayerName( this, 0, false ) ) {
|
||||||
|
@ -975,9 +987,9 @@ public class GamesList extends XWExpandableListActivity
|
||||||
private void updateField()
|
private void updateField()
|
||||||
{
|
{
|
||||||
String newField = CommonPrefs.getSummaryField( this );
|
String newField = CommonPrefs.getSummaryField( this );
|
||||||
if ( ! newField.equals( m_nameField ) ) {
|
if ( m_adapter.setField( newField ) ) {
|
||||||
m_nameField = newField;
|
// The adapter should be able to decide whether full
|
||||||
m_adapter.setField( newField );
|
// content change is required. PENDING
|
||||||
onContentChanged();
|
onContentChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1019,10 +1031,20 @@ public class GamesList extends XWExpandableListActivity
|
||||||
return madeGame;
|
return madeGame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void launchGame( long rowid, boolean invited )
|
||||||
|
{
|
||||||
|
GameUtils.launchGame( this, rowid, invited );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void launchGame( long rowid )
|
||||||
|
{
|
||||||
|
launchGame( rowid, false );
|
||||||
|
}
|
||||||
|
|
||||||
private void makeNewNetGame( NetLaunchInfo info )
|
private void makeNewNetGame( NetLaunchInfo info )
|
||||||
{
|
{
|
||||||
long rowid = GameUtils.makeNewNetGame( this, info );
|
long rowid = GameUtils.makeNewNetGame( this, info );
|
||||||
GameUtils.launchGame( this, rowid, true );
|
launchGame( rowid, true );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void onGameDictDownload( Context context, Intent intent )
|
public static void onGameDictDownload( Context context, Intent intent )
|
||||||
|
@ -1054,6 +1076,20 @@ public class GamesList extends XWExpandableListActivity
|
||||||
return intent;
|
return intent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Intent makeRematchIntent( Context context, CurGameInfo gi,
|
||||||
|
long rowid )
|
||||||
|
{
|
||||||
|
Intent intent = makeSelfIntent( context );
|
||||||
|
|
||||||
|
if ( CurGameInfo.DeviceRole.SERVER_STANDALONE == gi.serverRole ) {
|
||||||
|
intent.putExtra( REMATCH_ROWID_EXTRA, rowid );
|
||||||
|
} else {
|
||||||
|
Utils.notImpl( context );
|
||||||
|
}
|
||||||
|
|
||||||
|
return intent;
|
||||||
|
}
|
||||||
|
|
||||||
public static void openGame( Context context, Uri data )
|
public static void openGame( Context context, Uri data )
|
||||||
{
|
{
|
||||||
Intent intent = makeSelfIntent( context );
|
Intent intent = makeSelfIntent( context );
|
||||||
|
|
|
@ -43,7 +43,7 @@ abstract class InviteActivity extends XWListActivity
|
||||||
implements View.OnClickListener {
|
implements View.OnClickListener {
|
||||||
|
|
||||||
public static final String DEVS = "DEVS";
|
public static final String DEVS = "DEVS";
|
||||||
public static final String INTENT_KEY_NMISSING = "NMISSING";
|
protected static final String INTENT_KEY_NMISSING = "NMISSING";
|
||||||
|
|
||||||
protected int m_nMissing;
|
protected int m_nMissing;
|
||||||
protected Button m_okButton;
|
protected Button m_okButton;
|
||||||
|
|
|
@ -42,7 +42,7 @@ public class MultiService {
|
||||||
public static final int OWNER_SMS = 1;
|
public static final int OWNER_SMS = 1;
|
||||||
public static final int OWNER_RELAY = 2;
|
public static final int OWNER_RELAY = 2;
|
||||||
|
|
||||||
private BTEventListener m_li;
|
private MultiEventListener m_li;
|
||||||
|
|
||||||
public enum MultiEvent { BAD_PROTO
|
public enum MultiEvent { BAD_PROTO
|
||||||
, BT_ENABLED
|
, BT_ENABLED
|
||||||
|
@ -64,14 +64,14 @@ public class MultiService {
|
||||||
, SMS_SEND_FAILED_NORADIO
|
, SMS_SEND_FAILED_NORADIO
|
||||||
};
|
};
|
||||||
|
|
||||||
public interface BTEventListener {
|
public interface MultiEventListener {
|
||||||
public void eventOccurred( MultiEvent event, Object ... args );
|
public void eventOccurred( MultiEvent event, Object ... args );
|
||||||
}
|
}
|
||||||
// public interface MultiEventSrc {
|
// public interface MultiEventSrc {
|
||||||
// public void setBTEventListener( BTEventListener li );
|
// public void setBTEventListener( BTEventListener li );
|
||||||
// }
|
// }
|
||||||
|
|
||||||
public void setListener( BTEventListener li )
|
public void setListener( MultiEventListener li )
|
||||||
{
|
{
|
||||||
synchronized( this ) {
|
synchronized( this ) {
|
||||||
m_li = li;
|
m_li = li;
|
||||||
|
|
|
@ -73,7 +73,7 @@ public class NetLaunchInfo {
|
||||||
if ( null != data ) {
|
if ( null != data ) {
|
||||||
String scheme = data.getScheme();
|
String scheme = data.getScheme();
|
||||||
try {
|
try {
|
||||||
if ( "content".equals(scheme) ) {
|
if ( "content".equals(scheme) || "file".equals(scheme) ) {
|
||||||
Assert.assertNotNull( context );
|
Assert.assertNotNull( context );
|
||||||
ContentResolver resolver = context.getContentResolver();
|
ContentResolver resolver = context.getContentResolver();
|
||||||
InputStream is = resolver.openInputStream( data );
|
InputStream is = resolver.openInputStream( data );
|
||||||
|
|
|
@ -130,8 +130,7 @@ public class NetUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[][][] queryRelay( Context context, String[] ids,
|
public static byte[][][] queryRelay( Context context, String[] ids )
|
||||||
int nBytes )
|
|
||||||
{
|
{
|
||||||
byte[][][] msgs = null;
|
byte[][][] msgs = null;
|
||||||
try {
|
try {
|
||||||
|
@ -141,6 +140,7 @@ public class NetUtils {
|
||||||
new DataOutputStream( socket.getOutputStream() );
|
new DataOutputStream( socket.getOutputStream() );
|
||||||
|
|
||||||
// total packet size
|
// total packet size
|
||||||
|
int nBytes = sumStrings( ids );
|
||||||
outStream.writeShort( 2 + nBytes + ids.length + 1 );
|
outStream.writeShort( 2 + nBytes + ids.length + 1 );
|
||||||
|
|
||||||
outStream.writeByte( NetUtils.PROTOCOL_VERSION );
|
outStream.writeByte( NetUtils.PROTOCOL_VERSION );
|
||||||
|
@ -263,4 +263,16 @@ public class NetUtils {
|
||||||
DbgUtils.logf( "sendToRelay: null msgs" );
|
DbgUtils.logf( "sendToRelay: null msgs" );
|
||||||
}
|
}
|
||||||
} // sendToRelay
|
} // sendToRelay
|
||||||
|
|
||||||
|
private static int sumStrings( final String[] strs )
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
if ( null != strs ) {
|
||||||
|
for ( String str : strs ) {
|
||||||
|
len += str.length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -256,7 +256,7 @@ public class NewGameActivity extends XWActivity {
|
||||||
return dialog;
|
return dialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
// BTService.BTEventListener interface
|
// MultiService.MultiEventListener interface
|
||||||
@Override
|
@Override
|
||||||
public void eventOccurred( MultiService.MultiEvent event,
|
public void eventOccurred( MultiService.MultiEvent event,
|
||||||
final Object ... args )
|
final Object ... args )
|
||||||
|
@ -299,7 +299,7 @@ public class NewGameActivity extends XWActivity {
|
||||||
super.eventOccurred( event, args );
|
super.eventOccurred( event, args );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} // BTService.BTEventListener.eventOccurred
|
} // MultiService.MultiEventListener.eventOccurred
|
||||||
|
|
||||||
private void makeNewGame( boolean networked, boolean launch )
|
private void makeNewGame( boolean networked, boolean launch )
|
||||||
{
|
{
|
||||||
|
@ -357,7 +357,7 @@ public class NewGameActivity extends XWActivity {
|
||||||
intent.putExtra( GameUtils.INTENT_FORRESULT_ROWID, true );
|
intent.putExtra( GameUtils.INTENT_FORRESULT_ROWID, true );
|
||||||
startActivityForResult( intent, CONFIG_FOR_BT );
|
startActivityForResult( intent, CONFIG_FOR_BT );
|
||||||
} else {
|
} else {
|
||||||
GameUtils.launchBTInviter( this, 1, INVITE_FOR_BT );
|
BTInviteActivity.launchForResult( this, 1, INVITE_FOR_BT );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,7 +378,7 @@ public class NewGameActivity extends XWActivity {
|
||||||
intent.putExtra( GameUtils.INTENT_FORRESULT_ROWID, true );
|
intent.putExtra( GameUtils.INTENT_FORRESULT_ROWID, true );
|
||||||
startActivityForResult( intent, CONFIG_FOR_SMS );
|
startActivityForResult( intent, CONFIG_FOR_SMS );
|
||||||
} else {
|
} else {
|
||||||
GameUtils.launchSMSInviter( this, 1, INVITE_FOR_SMS );
|
SMSInviteActivity.launchForResult( this, 1, INVITE_FOR_SMS );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ public class RelayGameActivity extends XWActivity
|
||||||
|
|
||||||
private long m_rowid;
|
private long m_rowid;
|
||||||
private CurGameInfo m_gi;
|
private CurGameInfo m_gi;
|
||||||
private GameUtils.GameLock m_gameLock;
|
private GameLock m_gameLock;
|
||||||
private CommsAddrRec m_car;
|
private CommsAddrRec m_car;
|
||||||
private Button m_playButton;
|
private Button m_playButton;
|
||||||
private Button m_configButton;
|
private Button m_configButton;
|
||||||
|
@ -68,22 +68,28 @@ public class RelayGameActivity extends XWActivity
|
||||||
super.onStart();
|
super.onStart();
|
||||||
|
|
||||||
m_gi = new CurGameInfo( this );
|
m_gi = new CurGameInfo( this );
|
||||||
m_gameLock = new GameUtils.GameLock( m_rowid, true ).lock();
|
m_gameLock = new GameLock( m_rowid, true ).lock( 300 );
|
||||||
int gamePtr = GameUtils.loadMakeGame( this, m_gi, m_gameLock );
|
if ( null == m_gameLock ) {
|
||||||
m_car = new CommsAddrRec();
|
DbgUtils.logf( "RelayGameActivity.onStart(): unable to lock rowid %d",
|
||||||
if ( XwJNI.game_hasComms( gamePtr ) ) {
|
m_rowid );
|
||||||
XwJNI.comms_getAddr( gamePtr, m_car );
|
finish();
|
||||||
} else {
|
} else {
|
||||||
Assert.fail();
|
int gamePtr = GameUtils.loadMakeGame( this, m_gi, m_gameLock );
|
||||||
// String relayName = CommonPrefs.getDefaultRelayHost( this );
|
m_car = new CommsAddrRec();
|
||||||
// int relayPort = CommonPrefs.getDefaultRelayPort( this );
|
if ( XwJNI.game_hasComms( gamePtr ) ) {
|
||||||
// XwJNI.comms_getInitialAddr( m_carOrig, relayName, relayPort );
|
XwJNI.comms_getAddr( gamePtr, m_car );
|
||||||
}
|
} else {
|
||||||
XwJNI.game_dispose( gamePtr );
|
Assert.fail();
|
||||||
|
// String relayName = CommonPrefs.getDefaultRelayHost( this );
|
||||||
|
// int relayPort = CommonPrefs.getDefaultRelayPort( this );
|
||||||
|
// XwJNI.comms_getInitialAddr( m_carOrig, relayName, relayPort );
|
||||||
|
}
|
||||||
|
XwJNI.game_dispose( gamePtr );
|
||||||
|
|
||||||
String lang = DictLangCache.getLangName( this, m_gi.dictLang );
|
String lang = DictLangCache.getLangName( this, m_gi.dictLang );
|
||||||
TextView text = (TextView)findViewById( R.id.explain );
|
TextView text = (TextView)findViewById( R.id.explain );
|
||||||
text.setText( getString( R.string.relay_game_explainf, lang ) );
|
text.setText( getString( R.string.relay_game_explainf, lang ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -75,44 +75,39 @@ public class RelayService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String[] collectIDs( int[] nBytes )
|
|
||||||
{
|
|
||||||
String[] ids = DBUtils.getRelayIDs( this, false );
|
|
||||||
int len = 0;
|
|
||||||
if ( null != ids ) {
|
|
||||||
for ( String id : ids ) {
|
|
||||||
len += id.length();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nBytes[0] = len;
|
|
||||||
return ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void fetchAndProcess()
|
private void fetchAndProcess()
|
||||||
{
|
{
|
||||||
int[] nBytes = new int[1];
|
long[][] rowIDss = new long[1][];
|
||||||
String[] ids = collectIDs( nBytes );
|
String[] relayIDs = DBUtils.getRelayIDs( this, rowIDss );
|
||||||
if ( null != ids && 0 < ids.length ) {
|
if ( null != relayIDs && 0 < relayIDs.length ) {
|
||||||
RelayMsgSink sink = new RelayMsgSink();
|
long[] rowIDs = rowIDss[0];
|
||||||
byte[][][] msgs =
|
byte[][][] msgs = NetUtils.queryRelay( this, relayIDs );
|
||||||
NetUtils.queryRelay( this, ids, nBytes[0] );
|
|
||||||
|
|
||||||
if ( null != msgs ) {
|
if ( null != msgs ) {
|
||||||
int nameCount = ids.length;
|
RelayMsgSink sink = new RelayMsgSink();
|
||||||
|
int nameCount = relayIDs.length;
|
||||||
ArrayList<String> idsWMsgs =
|
ArrayList<String> idsWMsgs =
|
||||||
new ArrayList<String>( nameCount );
|
new ArrayList<String>( nameCount );
|
||||||
for ( int ii = 0; ii < nameCount; ++ii ) {
|
for ( int ii = 0; ii < nameCount; ++ii ) {
|
||||||
|
byte[][] forOne = msgs[ii];
|
||||||
// if game has messages, open it and feed 'em
|
// if game has messages, open it and feed 'em
|
||||||
// to it.
|
// to it.
|
||||||
if ( GameUtils.feedMessages( this, ids[ii],
|
if ( null == forOne ) {
|
||||||
msgs[ii], sink ) ) {
|
// Nothing for this relayID
|
||||||
idsWMsgs.add( ids[ii] );
|
} else if ( BoardActivity.feedMessages( rowIDs[ii], forOne )
|
||||||
|
|| GameUtils.feedMessages( this, rowIDs[ii],
|
||||||
|
forOne, null,
|
||||||
|
sink ) ) {
|
||||||
|
idsWMsgs.add( relayIDs[ii] );
|
||||||
|
} else {
|
||||||
|
DbgUtils.logf( "dropping message for %s (rowid %d)",
|
||||||
|
relayIDs[ii], rowIDs[ii] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( 0 < idsWMsgs.size() ) {
|
if ( 0 < idsWMsgs.size() ) {
|
||||||
String[] relayIDs = new String[idsWMsgs.size()];
|
String[] tmp = new String[idsWMsgs.size()];
|
||||||
idsWMsgs.toArray( relayIDs );
|
idsWMsgs.toArray( tmp );
|
||||||
setupNotification( relayIDs );
|
setupNotification( tmp );
|
||||||
}
|
}
|
||||||
sink.send( this );
|
sink.send( this );
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,9 +32,9 @@ import android.os.Bundle;
|
||||||
import android.provider.ContactsContract.CommonDataKinds.Phone;
|
import android.provider.ContactsContract.CommonDataKinds.Phone;
|
||||||
import android.provider.ContactsContract.CommonDataKinds;
|
import android.provider.ContactsContract.CommonDataKinds;
|
||||||
import android.provider.ContactsContract;
|
import android.provider.ContactsContract;
|
||||||
import android.text.method.DialerKeyListener;
|
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
|
import android.text.method.DialerKeyListener;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.CompoundButton;
|
import android.widget.CompoundButton;
|
||||||
|
@ -64,6 +64,14 @@ public class SMSInviteActivity extends InviteActivity {
|
||||||
private String m_pendingNumber;
|
private String m_pendingNumber;
|
||||||
private boolean m_immobileConfirmed;
|
private boolean m_immobileConfirmed;
|
||||||
|
|
||||||
|
public static void launchForResult( Activity activity, int nMissing,
|
||||||
|
int requestCode )
|
||||||
|
{
|
||||||
|
Intent intent = new Intent( activity, SMSInviteActivity.class );
|
||||||
|
intent.putExtra( INTENT_KEY_NMISSING, nMissing );
|
||||||
|
activity.startActivityForResult( intent, requestCode );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate( Bundle savedInstanceState )
|
protected void onCreate( Bundle savedInstanceState )
|
||||||
{
|
{
|
||||||
|
|
|
@ -189,7 +189,7 @@ public class SMSService extends Service {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setListener( MultiService.BTEventListener li )
|
public static void setListener( MultiService.MultiEventListener li )
|
||||||
{
|
{
|
||||||
if ( XWApp.SMSSUPPORTED ) {
|
if ( XWApp.SMSSUPPORTED ) {
|
||||||
if ( null == s_srcMgr ) {
|
if ( null == s_srcMgr ) {
|
||||||
|
|
|
@ -40,6 +40,8 @@ import android.net.Uri;
|
||||||
import android.provider.ContactsContract.PhoneLookup;
|
import android.provider.ContactsContract.PhoneLookup;
|
||||||
import android.telephony.TelephonyManager;
|
import android.telephony.TelephonyManager;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.CheckBox;
|
import android.widget.CheckBox;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
|
@ -345,6 +347,12 @@ public class Utils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void setItemVisible( Menu menu, int id, boolean enabled )
|
||||||
|
{
|
||||||
|
MenuItem item = menu.findItem( id );
|
||||||
|
item.setVisible( enabled );
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean hasSmallScreen( Context context )
|
public static boolean hasSmallScreen( Context context )
|
||||||
{
|
{
|
||||||
if ( null == s_hasSmallScreen ) {
|
if ( null == s_hasSmallScreen ) {
|
||||||
|
|
|
@ -31,7 +31,7 @@ import android.widget.TextView;
|
||||||
import junit.framework.Assert;
|
import junit.framework.Assert;
|
||||||
|
|
||||||
public class XWActivity extends Activity
|
public class XWActivity extends Activity
|
||||||
implements DlgDelegate.DlgClickNotify, MultiService.BTEventListener {
|
implements DlgDelegate.DlgClickNotify, MultiService.MultiEventListener {
|
||||||
|
|
||||||
private DlgDelegate m_delegate;
|
private DlgDelegate m_delegate;
|
||||||
|
|
||||||
|
@ -192,7 +192,7 @@ public class XWActivity extends Activity
|
||||||
Assert.fail();
|
Assert.fail();
|
||||||
}
|
}
|
||||||
|
|
||||||
// BTService.BTEventListener interface
|
// BTService.MultiEventListener interface
|
||||||
public void eventOccurred( MultiService.MultiEvent event,
|
public void eventOccurred( MultiService.MultiEvent event,
|
||||||
final Object ... args )
|
final Object ... args )
|
||||||
{
|
{
|
||||||
|
|
|
@ -28,12 +28,14 @@ import java.util.UUID;
|
||||||
import org.eehouse.android.xw4.jni.XwJNI;
|
import org.eehouse.android.xw4.jni.XwJNI;
|
||||||
|
|
||||||
public class XWApp extends Application {
|
public class XWApp extends Application {
|
||||||
public static final boolean DEBUG_LOCKS = false;
|
|
||||||
public static final boolean BTSUPPORTED = false;
|
public static final boolean BTSUPPORTED = false;
|
||||||
public static final boolean SMSSUPPORTED = true;
|
public static final boolean SMSSUPPORTED = true;
|
||||||
public static final boolean GCMSUPPORTED = true;
|
public static final boolean GCMSUPPORTED = true;
|
||||||
public static final boolean ATTACH_SUPPORTED = false;
|
public static final boolean ATTACH_SUPPORTED = true;
|
||||||
|
public static final boolean REMATCH_SUPPORTED = false;
|
||||||
public static final boolean DEBUG = true;
|
public static final boolean DEBUG = true;
|
||||||
|
public static final boolean DEBUG_LOCKS = false && DEBUG;
|
||||||
|
public static final boolean DEBUG_EXP_TIMERS = false && DEBUG;
|
||||||
|
|
||||||
public static final String SMS_PUBLIC_HEADER = "-XW4";
|
public static final String SMS_PUBLIC_HEADER = "-XW4";
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ import android.os.Bundle;
|
||||||
import junit.framework.Assert;
|
import junit.framework.Assert;
|
||||||
|
|
||||||
public class XWListActivity extends ListActivity
|
public class XWListActivity extends ListActivity
|
||||||
implements DlgDelegate.DlgClickNotify, MultiService.BTEventListener {
|
implements DlgDelegate.DlgClickNotify, MultiService.MultiEventListener {
|
||||||
|
|
||||||
private DlgDelegate m_delegate;
|
private DlgDelegate m_delegate;
|
||||||
|
|
||||||
|
@ -187,7 +187,7 @@ public class XWListActivity extends ListActivity
|
||||||
m_delegate.launchLookup( words, lang, forceList );
|
m_delegate.launchLookup( words, lang, forceList );
|
||||||
}
|
}
|
||||||
|
|
||||||
// BTService.BTEventListener interface
|
// MultiService.MultiEventListener interface
|
||||||
public void eventOccurred( MultiService.MultiEvent event,
|
public void eventOccurred( MultiService.MultiEvent event,
|
||||||
final Object ... args )
|
final Object ... args )
|
||||||
{
|
{
|
||||||
|
|
|
@ -41,11 +41,14 @@ public abstract class XWListAdapter implements ListAdapter {
|
||||||
public boolean areAllItemsEnabled() { return true; }
|
public boolean areAllItemsEnabled() { return true; }
|
||||||
public boolean isEnabled( int position ) { return true; }
|
public boolean isEnabled( int position ) { return true; }
|
||||||
public int getCount() { return m_count; }
|
public int getCount() { return m_count; }
|
||||||
public long getItemId(int position) { return position; }
|
public Object getItem( int position ) { return null; }
|
||||||
public int getItemViewType(int position) { return 0; }
|
public long getItemId( int position ) { return position; }
|
||||||
|
public int getItemViewType( int position ) {
|
||||||
|
return ListAdapter.IGNORE_ITEM_VIEW_TYPE;
|
||||||
|
}
|
||||||
public int getViewTypeCount() { return 1; }
|
public int getViewTypeCount() { return 1; }
|
||||||
public boolean hasStableIds() { return true; }
|
public boolean hasStableIds() { return true; }
|
||||||
public boolean isEmpty() { return getCount() == 0; }
|
public boolean isEmpty() { return getCount() == 0; }
|
||||||
public void registerDataSetObserver(DataSetObserver observer) {}
|
public void registerDataSetObserver( DataSetObserver observer ) {}
|
||||||
public void unregisterDataSetObserver(DataSetObserver observer) {}
|
public void unregisterDataSetObserver( DataSetObserver observer ) {}
|
||||||
}
|
}
|
|
@ -83,6 +83,11 @@ public class XWPrefs {
|
||||||
return getPrefsBoolean( context, R.string.key_ringer_zoom, false );
|
return getPrefsBoolean( context, R.string.key_ringer_zoom, false );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean getSquareTiles( Context context )
|
||||||
|
{
|
||||||
|
return getPrefsBoolean( context, R.string.key_square_tiles, false );
|
||||||
|
}
|
||||||
|
|
||||||
public static int getDefaultPlayerMinutes( Context context )
|
public static int getDefaultPlayerMinutes( Context context )
|
||||||
{
|
{
|
||||||
String value =
|
String value =
|
||||||
|
|
|
@ -34,6 +34,7 @@ import org.eehouse.android.xw4.R;
|
||||||
import org.eehouse.android.xw4.DbgUtils;
|
import org.eehouse.android.xw4.DbgUtils;
|
||||||
import org.eehouse.android.xw4.ConnStatusHandler;
|
import org.eehouse.android.xw4.ConnStatusHandler;
|
||||||
import org.eehouse.android.xw4.BoardDims;
|
import org.eehouse.android.xw4.BoardDims;
|
||||||
|
import org.eehouse.android.xw4.GameLock;
|
||||||
import org.eehouse.android.xw4.GameUtils;
|
import org.eehouse.android.xw4.GameUtils;
|
||||||
import org.eehouse.android.xw4.DBUtils;
|
import org.eehouse.android.xw4.DBUtils;
|
||||||
import org.eehouse.android.xw4.Toolbar;
|
import org.eehouse.android.xw4.Toolbar;
|
||||||
|
@ -94,6 +95,7 @@ public class JNIThread extends Thread {
|
||||||
public static final int QUERY_ENDGAME = 4;
|
public static final int QUERY_ENDGAME = 4;
|
||||||
public static final int TOOLBAR_STATES = 5;
|
public static final int TOOLBAR_STATES = 5;
|
||||||
public static final int GOT_WORDS = 6;
|
public static final int GOT_WORDS = 6;
|
||||||
|
public static final int GAME_OVER = 7;
|
||||||
|
|
||||||
public class GameStateInfo implements Cloneable {
|
public class GameStateInfo implements Cloneable {
|
||||||
public int visTileCount;
|
public int visTileCount;
|
||||||
|
@ -120,7 +122,7 @@ public class JNIThread extends Thread {
|
||||||
private boolean m_stopped = false;
|
private boolean m_stopped = false;
|
||||||
private boolean m_saveOnStop = false;
|
private boolean m_saveOnStop = false;
|
||||||
private int m_jniGamePtr;
|
private int m_jniGamePtr;
|
||||||
private GameUtils.GameLock m_lock;
|
private GameLock m_lock;
|
||||||
private Context m_context;
|
private Context m_context;
|
||||||
private CurGameInfo m_gi;
|
private CurGameInfo m_gi;
|
||||||
private Handler m_handler;
|
private Handler m_handler;
|
||||||
|
@ -142,7 +144,7 @@ public class JNIThread extends Thread {
|
||||||
}
|
}
|
||||||
|
|
||||||
public JNIThread( int gamePtr, CurGameInfo gi, SyncedDraw drawer,
|
public JNIThread( int gamePtr, CurGameInfo gi, SyncedDraw drawer,
|
||||||
GameUtils.GameLock lock, Context context, Handler handler )
|
GameLock lock, Context context, Handler handler )
|
||||||
{
|
{
|
||||||
m_jniGamePtr = gamePtr;
|
m_jniGamePtr = gamePtr;
|
||||||
m_gi = gi;
|
m_gi = gi;
|
||||||
|
@ -524,8 +526,14 @@ public class JNIThread extends Thread {
|
||||||
|
|
||||||
case CMD_POST_OVER:
|
case CMD_POST_OVER:
|
||||||
if ( XwJNI.server_getGameIsOver( m_jniGamePtr ) ) {
|
if ( XwJNI.server_getGameIsOver( m_jniGamePtr ) ) {
|
||||||
sendForDialog( R.string.finalscores_title,
|
boolean auto = 0 < args.length &&
|
||||||
XwJNI.server_writeFinalScores( m_jniGamePtr ) );
|
((Boolean)args[0]).booleanValue();
|
||||||
|
int titleID = auto? R.string.summary_gameover
|
||||||
|
: R.string.finalscores_title;
|
||||||
|
|
||||||
|
String text = XwJNI.server_writeFinalScores( m_jniGamePtr );
|
||||||
|
Message.obtain( m_handler, GAME_OVER, titleID, 0, text )
|
||||||
|
.sendToTarget();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -30,16 +30,17 @@ function printNonAndroid($agent) {
|
||||||
$subject = "Android device not identified";
|
$subject = "Android device not identified";
|
||||||
|
|
||||||
$body = htmlentities("My browser is running on an android device but"
|
$body = htmlentities("My browser is running on an android device but"
|
||||||
. " says its user agent is: \"$agent\". Please fix your script to recognize"
|
. " says its user agent is: \"$agent\"."
|
||||||
|
. " Please fix your website to recognize"
|
||||||
. " this as an Android browser.");
|
. " this as an Android browser.");
|
||||||
print <<<EOF
|
print <<<EOF
|
||||||
<div class="center">
|
<div class="center">
|
||||||
<p>This page is meant to be viewed on an Android device.</p>
|
<p>This page is meant to be viewed on an Android device.</p>
|
||||||
<hr>
|
<hr>
|
||||||
<p>(If you <em>are</em> viewing this on an Android device, you've
|
<p>(If you <em>are</em> viewing this on an Android device,
|
||||||
found a bug! Please <a href="mailto:
|
you've found a bug! Please <a href="mailto:
|
||||||
xwords@eehouse.org?subject=$subject&body=$body">email me</a> (and be
|
xwords@eehouse.org?subject=$subject&body=$body">email me</a>
|
||||||
sure to leave the user agent string in the email body.)
|
(and be sure to leave the user agent string in the email body.)
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -73,6 +74,11 @@ invite email (or text) and tap the link again.</p>
|
||||||
link in your invite email (or text) again, and this time let
|
link in your invite email (or text) again, and this time let
|
||||||
Crosswords handle it.</p>
|
Crosswords handle it.</p>
|
||||||
|
|
||||||
|
<p>(If you get tired of having to having to make that choice, Android
|
||||||
|
will allow you to make Crosswords the default. If you do that
|
||||||
|
Crosswords will be given control of all URLs that start with
|
||||||
|
"http://eehouse.org/and/" -- not all URLs of any type.)</p>
|
||||||
|
|
||||||
<p>Have fun. And as always, <a href="mailto:xwords@eehouse.org">let
|
<p>Have fun. And as always, <a href="mailto:xwords@eehouse.org">let
|
||||||
me know</a> if you have problems or suggestions.</p>
|
me know</a> if you have problems or suggestions.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -93,10 +93,12 @@ game_makeNewGame( MPFORMAL XWGame* game, CurGameInfo* gi,
|
||||||
#endif
|
#endif
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
XP_U16 nPlayersHere, nPlayersTotal;
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
||||||
|
XP_U16 nPlayersHere = 0;
|
||||||
assertUtilOK( util );
|
XP_U16 nPlayersTotal = 0;
|
||||||
checkServerRole( gi, &nPlayersHere, &nPlayersTotal );
|
checkServerRole( gi, &nPlayersHere, &nPlayersTotal );
|
||||||
|
#endif
|
||||||
|
assertUtilOK( util );
|
||||||
|
|
||||||
gi->gameID = makeGameID( util );
|
gi->gameID = makeGameID( util );
|
||||||
|
|
||||||
|
@ -137,15 +139,17 @@ game_reset( MPFORMAL XWGame* game, CurGameInfo* gi,
|
||||||
CommonPrefs* cp, const TransportProcs* procs )
|
CommonPrefs* cp, const TransportProcs* procs )
|
||||||
{
|
{
|
||||||
XP_U16 ii;
|
XP_U16 ii;
|
||||||
XP_U16 nPlayersHere, nPlayersTotal;
|
|
||||||
|
|
||||||
XP_ASSERT( !!game->model );
|
XP_ASSERT( !!game->model );
|
||||||
XP_ASSERT( !!gi );
|
XP_ASSERT( !!gi );
|
||||||
|
|
||||||
checkServerRole( gi, &nPlayersHere, &nPlayersTotal );
|
|
||||||
gi->gameID = makeGameID( util );
|
gi->gameID = makeGameID( util );
|
||||||
|
|
||||||
#ifndef XWFEATURE_STANDALONE_ONLY
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
||||||
|
XP_U16 nPlayersHere = 0;
|
||||||
|
XP_U16 nPlayersTotal = 0;
|
||||||
|
checkServerRole( gi, &nPlayersHere, &nPlayersTotal );
|
||||||
|
|
||||||
if ( !!game->comms ) {
|
if ( !!game->comms ) {
|
||||||
if ( gi->serverRole == SERVER_STANDALONE ) {
|
if ( gi->serverRole == SERVER_STANDALONE ) {
|
||||||
comms_destroy( game->comms );
|
comms_destroy( game->comms );
|
||||||
|
|
|
@ -686,7 +686,7 @@ handleRegistrationMsg( ServerCtxt* server, XWStreamCtxt* stream )
|
||||||
{
|
{
|
||||||
XP_Bool success = XP_TRUE;
|
XP_Bool success = XP_TRUE;
|
||||||
XP_U16 playersInMsg;
|
XP_U16 playersInMsg;
|
||||||
XP_S8 clientIndex;
|
XP_S8 clientIndex = 0; /* quiet compiler */
|
||||||
XP_U16 ii = 0;
|
XP_U16 ii = 0;
|
||||||
LOG_FUNC();
|
LOG_FUNC();
|
||||||
|
|
||||||
|
|
|
@ -55,13 +55,19 @@ def init():
|
||||||
def getPendingMsgs( con, typ ):
|
def getPendingMsgs( con, typ ):
|
||||||
cur = con.cursor()
|
cur = con.cursor()
|
||||||
query = """SELECT id, devid FROM msgs
|
query = """SELECT id, devid FROM msgs
|
||||||
WHERE devid IN (SELECT id FROM devices WHERE devtype=%d)
|
WHERE devid IN (SELECT id FROM devices WHERE devtype=%d and NOT unreg)
|
||||||
AND NOT connname IN (SELECT connname FROM games WHERE dead); """
|
AND NOT connname IN (SELECT connname FROM games WHERE dead); """
|
||||||
cur.execute(query % typ)
|
cur.execute(query % typ)
|
||||||
result = cur.fetchall()
|
result = cur.fetchall()
|
||||||
if g_debug: print "getPendingMsgs=>", result
|
if g_debug: print "getPendingMsgs=>", result
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def unregister( gcmid ):
|
||||||
|
global g_con
|
||||||
|
print "unregister(", gcmid, ")"
|
||||||
|
query = "UPDATE devices SET unreg=TRUE WHERE id = '%s'" % gcmid
|
||||||
|
g_con.cursor().execute( query )
|
||||||
|
|
||||||
def asGCMIds(con, devids, typ):
|
def asGCMIds(con, devids, typ):
|
||||||
cur = con.cursor()
|
cur = con.cursor()
|
||||||
query = "SELECT devid FROM devices WHERE devtype = %d AND id IN (%s)" \
|
query = "SELECT devid FROM devices WHERE devtype = %d AND id IN (%s)" \
|
||||||
|
@ -72,20 +78,15 @@ def asGCMIds(con, devids, typ):
|
||||||
def notifyGCM( devids, typ ):
|
def notifyGCM( devids, typ ):
|
||||||
if typ == DEVTYPE_GCM:
|
if typ == DEVTYPE_GCM:
|
||||||
instance = gcm.GCM( mykey.myKey )
|
instance = gcm.GCM( mykey.myKey )
|
||||||
data = { 'getMoves': True,
|
data = { 'getMoves': True, }
|
||||||
# 'title' : 'Msg from Darth',
|
|
||||||
# 'msg' : "I am your father, Luke.",
|
|
||||||
}
|
|
||||||
response = instance.json_request( registration_ids = devids,
|
response = instance.json_request( registration_ids = devids,
|
||||||
# restricted_package_name = 'org.eehouse.android.xw4',
|
|
||||||
data = data,
|
data = data,
|
||||||
# collapse_key = 'NewMove',
|
|
||||||
)
|
)
|
||||||
if 'errors' in response:
|
if 'errors' in response:
|
||||||
response = response['errors']
|
response = response['errors']
|
||||||
if 'NotRegistered' in response:
|
if 'NotRegistered' in response:
|
||||||
for id in response['NotRegistered']:
|
for gcmid in response['NotRegistered']:
|
||||||
print 'need to remove "', id, '" from db'
|
unregister( gcmid )
|
||||||
else:
|
else:
|
||||||
print "got some kind of error"
|
print "got some kind of error"
|
||||||
else:
|
else:
|
||||||
|
@ -184,6 +185,7 @@ def main():
|
||||||
print "devices needing notification:", targets
|
print "devices needing notification:", targets
|
||||||
notifyGCM( asGCMIds( g_con, targets, typ ), typ )
|
notifyGCM( asGCMIds( g_con, targets, typ ), typ )
|
||||||
pruneSent( devids )
|
pruneSent( devids )
|
||||||
|
elif g_debug: print "no targets after backoff"
|
||||||
else:
|
else:
|
||||||
emptyCount += 1
|
emptyCount += 1
|
||||||
if (0 == (emptyCount%5)) and not g_debug:
|
if (0 == (emptyCount%5)) and not g_debug:
|
||||||
|
|
Loading…
Add table
Reference in a new issue