merge android_branch -> android_sms_kitkat

This commit is contained in:
Eric House 2014-04-26 18:31:05 -07:00
commit fbb042ffee
252 changed files with 10149 additions and 5651 deletions

1
.gitignore vendored
View file

@ -1,5 +1,6 @@
# ignore backups anywhere # ignore backups anywhere
*.~?~ *.~?~
*~
/gitignored /gitignored
TAGS TAGS
core core

View file

@ -4,4 +4,15 @@ tags:
-o -name '*.h' -print \ -o -name '*.h' -print \
-o -name '*.cpp' -print \ -o -name '*.cpp' -print \
) )
find android/XWords4/src/ -name '*.java' | xargs etags -a FILES=""; \
for f in $$(find android/ -name '*.java' -o -name '*.xml'); do \
DIR=$$(dirname $$f); \
if [ -e $$DIR/.gitignore ]; then \
if grep -q $$(basename $$f) $$DIR/.gitignore; then \
echo "skipping $$f"; \
f=""; \
fi; \
fi; \
[ "$$f" != "" ] && FILES="$$FILES $$f"; \
done; \
etags -a $$FILES

View file

@ -3,4 +3,7 @@ local.properties
bin bin
gen gen
proguard.cfg proguard.cfg
proguard-project.txt
obj obj
res/drawable*/*gen.png
img_src

View file

@ -22,7 +22,7 @@
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.xw4bt" package="org.eehouse.android.xw4bt"
android:versionCode="68" android:versionCode="72"
android:versionName="@string/app_version" android:versionName="@string/app_version"
> >
@ -45,6 +45,7 @@
<uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.RECEIVE_SMS" /> <uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.SEND_SMS" /> <uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.READ_CONTACTS" />
@ -129,6 +130,10 @@
android:theme="@android:style/Theme.Dialog" android:theme="@android:style/Theme.Dialog"
/> />
<activity android:name="StudyList"
android:configChanges="keyboardHidden|orientation|screenSize"
/>
<receiver android:name="RelayReceiver"> <receiver android:name="RelayReceiver">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/> <action android:name="android.intent.action.BOOT_COMPLETED"/>
@ -144,7 +149,6 @@
<activity android:name="DispatchNotify"> <activity android:name="DispatchNotify">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.EDIT" />
<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:scheme="newxwgame"/> <data android:scheme="newxwgame"/>

View file

@ -80,6 +80,8 @@
<arg value="--dest-dir"/> <arg value="--dest-dir"/>
<arg value="./assets"/> <arg value="./assets"/>
<arg value="--dest-dir"/> <arg value="--dest-dir"/>
<arg value="./libs"/>
<arg value="--dest-dir"/>
<arg value="./img_src"/> <arg value="./img_src"/>
</exec> </exec>
<exec dir="." executable="../scripts/ndksetup.sh" output="/dev/null"> <exec dir="." executable="../scripts/ndksetup.sh" output="/dev/null">

View file

@ -68,6 +68,7 @@ COMMON_SRC_FILES += \
$(COMMON_PATH)/tray.c \ $(COMMON_PATH)/tray.c \
$(COMMON_PATH)/dictnry.c \ $(COMMON_PATH)/dictnry.c \
$(COMMON_PATH)/dictiter.c \ $(COMMON_PATH)/dictiter.c \
$(COMMON_PATH)/dictmgr.c \
$(COMMON_PATH)/mscore.c \ $(COMMON_PATH)/mscore.c \
$(COMMON_PATH)/vtabmgr.c \ $(COMMON_PATH)/vtabmgr.c \
$(COMMON_PATH)/strutils.c \ $(COMMON_PATH)/strutils.c \
@ -90,5 +91,10 @@ LOCAL_LDLIBS := -L${SYSROOT}/usr/lib -llog -lz
include $(BUILD_SHARED_LIBRARY) include $(BUILD_SHARED_LIBRARY)
ifneq ($(shell which ccache),)
TARGET_CC = ccache $(TOOLCHAIN_PREFIX)gcc
TARGET_CXX = ccache $(TOOLCHAIN_PREFIX)g++
endif
COMMON_SRC_FILES := COMMON_SRC_FILES :=
COMMON_PATH := COMMON_PATH :=

View file

@ -1 +1,3 @@
/armeabi armeabi
x86
gcm.jar

View file

@ -14,3 +14,7 @@ reset__gen.png
save__gen.png save__gen.png
send__gen.png send__gen.png
up__gen.png up__gen.png
content_copy__gen.png
clear_all__gen.png
search__gen.png
select_all__gen.png

View file

@ -14,3 +14,7 @@ reset__gen.png
save__gen.png save__gen.png
send__gen.png send__gen.png
up__gen.png up__gen.png
content_copy__gen.png
clear_all__gen.png
search__gen.png
select_all__gen.png

View file

@ -14,3 +14,7 @@ reset__gen.png
save__gen.png save__gen.png
send__gen.png send__gen.png
up__gen.png up__gen.png
content_copy__gen.png
clear_all__gen.png
search__gen.png
select_all__gen.png

View file

@ -31,3 +31,4 @@ smsinviter_item.xml
smsinviter.xml smsinviter.xml
confirm_sms.xml confirm_sms.xml
game_list_group.xml game_list_group.xml
studylist.xml

View file

@ -4,3 +4,4 @@ dicts_item_menu.xml
games_list_item_menu.xml games_list_item_menu.xml
games_list_menu.xml games_list_menu.xml
dicts_menu.xml dicts_menu.xml
studylist.xml

View file

@ -78,3 +78,10 @@ XWPrefs.java
XWService.java XWService.java
XWSumListPreference.java XWSumListPreference.java
XWThumbListPreference.java XWThumbListPreference.java
StudyList.java
CrashTrack.java
DelegateBase.java
DlgID.java
GamesListActivity.java
GamesListDelegate.java
LookupAlert.java

View file

@ -3,6 +3,5 @@ ant_out.txt
local.properties local.properties
bin bin
gen gen
libs
proguard.cfg proguard.cfg
obj obj

View file

@ -22,19 +22,48 @@
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.xw4dbg" package="org.eehouse.android.xw4dbg"
android:versionCode="34" android:versionCode="73"
android:versionName="@string/app_version" android:versionName="@string/app_version"
> >
<!-- BE SURE TO MODIFY project.project AND the variable TARGET in
../scripts/setup_local_props.sh if targetSdkVersion changes!!!
-->
<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="14" />
<supports-screens android:resizeable="true"
android:smallScreens="true"
android:normalScreens="true"
android:largeScreens="true"
android:xlargeScreens="true"
/>
<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" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.VIBRATE" />
<!-- <uses-permission android:name="android.permission.RECEIVE_SMS" /> --> <uses-permission android:name="android.permission.RECEIVE_SMS" />
<!-- <uses-permission android:name="android.permission.SEND_SMS" /> --> <uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-sdk android:minSdkVersion="3" android:targetSdkVersion="5" /> <uses-feature android:name="android.hardware.telephony"
android:required = "false"
/>
<uses-feature android:name="android.hardware.nfc" android:required="false" />
<!-- GCM stuff -->
<permission android:name="org.eehouse.android.xw4.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="org.eehouse.android.xw4.permission.C2D_MESSAGE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.NFC" />
<!-- for crittercism -->
<uses-permission android:name="android.permission.GET_TASKS"/>
<application android:icon="@drawable/icon48x48" <application android:icon="@drawable/icon48x48"
android:label="@string/app_name" android:label="@string/app_name"
@ -44,26 +73,39 @@
<activity android:name="GamesList" <activity android:name="GamesList"
android:label="@string/app_name" android:label="@string/app_name"
android:launchMode="standard" android:launchMode="standard"
android:configChanges="keyboardHidden|orientation" android:configChanges="keyboardHidden|orientation|screenSize"
> >
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="@string/xwords_nfc_mime" />
</intent-filter>
</activity> </activity>
<activity android:name="DictsActivity" <activity android:name="DictsActivity"
android:label="@string/title_dicts_list" android:label="@string/title_dicts_list"
android:configChanges="keyboardHidden|orientation" android:configChanges="keyboardHidden|orientation|screenSize"
/> />
<activity android:name="NewGameActivity" <activity android:name="NewGameActivity"
android:theme="@android:style/Theme.NoTitleBar" android:theme="@android:style/Theme.NoTitleBar"
android:configChanges="keyboardHidden|orientation|screenSize"
/>
<activity android:name="SMSInviteActivity"
android:theme="@android:style/Theme.Dialog"
android:configChanges="keyboardHidden|orientation|screenSize"
android:screenOrientation="portrait"
/> />
<activity android:name="GameConfig" <activity android:name="GameConfig"
android:screenOrientation="sensor" android:screenOrientation="sensor"
android:configChanges="keyboardHidden|orientation" android:configChanges="keyboardHidden|orientation|screenSize"
> >
<intent-filter> <intent-filter>
<action android:name="android.intent.action.EDIT" /> <action android:name="android.intent.action.EDIT" />
@ -73,15 +115,22 @@
<activity android:name="PrefsActivity" <activity android:name="PrefsActivity"
android:label="@string/title_prefs" android:label="@string/title_prefs"
android:screenOrientation="sensor" android:screenOrientation="sensor"
> android:configChanges="keyboardHidden|orientation|screenSize"
</activity> />
<activity android:name="BoardActivity" <activity android:name="BoardActivity"
android:theme="@android:style/Theme.Light"
android:screenOrientation="portrait" android:screenOrientation="portrait"
android:configChanges="keyboardHidden" android:configChanges="keyboardHidden"
> />
</activity>
<activity android:name="LookupActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:theme="@android:style/Theme.Dialog"
/>
<activity android:name="StudyList"
android:configChanges="keyboardHidden|orientation|screenSize"
/>
<receiver android:name="RelayReceiver"> <receiver android:name="RelayReceiver">
<intent-filter> <intent-filter>
@ -89,15 +138,37 @@
</intent-filter> </intent-filter>
</receiver> </receiver>
<activity android:name="DispatchNotify" <receiver android:name="UpdateCheckReceiver">
> <intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
<activity android:name="DispatchNotify">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.EDIT" />
<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:scheme="newxwgame"/> <data android:scheme="newxwgame"/>
</intent-filter> </intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http"
android:host="@string/invite_host"
android:pathPrefix="@string/invite_prefix"
/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:mimeType="@string/invite_mime" />
</intent-filter>
</activity> </activity>
<!-- downloading dicts --> <!-- downloading dicts -->
@ -119,10 +190,10 @@
<activity android:name="RelayGameActivity"/> <activity android:name="RelayGameActivity"/>
<activity android:name="DictBrowseActivity" <activity android:name="DictBrowseActivity"
android:configChanges="keyboardHidden|orientation" android:configChanges="keyboardHidden|orientation|screenSize"
/> />
<activity android:name="ChatActivity" <activity android:name="ChatActivity"
android:configChanges="keyboardHidden|orientation" android:configChanges="keyboardHidden|orientation|screenSize"
/> />
<service android:name="RelayService"/> <service android:name="RelayService"/>
@ -138,14 +209,24 @@
</intent-filter> </intent-filter>
</receiver> </receiver>
<receiver android:name="SMSReceiver" >
<intent-filter android:priority="999" >
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
<!-- <receiver android:name="NBSReceiver"> --> <service android:name="SMSService"/>
<!-- <intent-filter android:priority="10"> -->
<!-- <action android:name="android.intent.action.DATA_SMS_RECEIVED" /> --> <receiver android:name="com.google.android.gcm.GCMBroadcastReceiver"
<!-- <data android:scheme="sms" /> --> android:permission="com.google.android.c2dm.permission.SEND" >
<!-- <data android:port="50009" /> --> <intent-filter>
<!-- </intent-filter> --> <action android:name="com.google.android.c2dm.intent.RECEIVE" />
<!-- </receiver> --> <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="org.eehouse.android.xw4" />
</intent-filter>
</receiver>
<service android:name=".GCMIntentService" />
</application> </application>
</manifest> </manifest>

View file

@ -49,16 +49,28 @@
<!-- extension targets. Uncomment the ones where you want to do custom work <!-- extension targets. Uncomment the ones where you want to do custom work
in between standard targets --> in between standard targets -->
<property name="INITIAL_CLIENT_VERS" value="3"/>
<target name="-pre-clean"> <target name="-pre-clean">
<exec dir="." executable="../scripts/ndkbuild.sh" output="/dev/null" > <exec dir="." executable="../scripts/ndksetup.sh" output="/dev/null">
<arg value="${build.target}"/>
</exec>
<exec dir="." executable="../scripts/ndkbuild.sh" output="/dev/null">
<arg value="clean"/> <arg value="clean"/>
</exec> </exec>
<exec dir="." executable="../scripts/mkimages.sh"
failonerror="true" >
<arg value="--clean"/>
</exec>
</target> </target>
<target name="-pre-build"> <target name="-pre-build">
<exec dir="." executable="../scripts/mkvariant.sh" output="/dev/null" > <exec dir="." executable="../scripts/mkvariant.sh" failonerror="true"
output="/dev/null">
<arg value="--variant-name"/> <arg value="--variant-name"/>
<arg value="xw4dbg"/> <arg value="xw4dbg"/>
<arg value="--app-name"/>
<arg value="cWords-DBG"/>
<arg value="--dest-dir"/> <arg value="--dest-dir"/>
<arg value="./res"/> <arg value="./res"/>
<arg value="--dest-dir"/> <arg value="--dest-dir"/>
@ -67,15 +79,42 @@
<arg value="./jni"/> <arg value="./jni"/>
<arg value="--dest-dir"/> <arg value="--dest-dir"/>
<arg value="./assets"/> <arg value="./assets"/>
<arg value="--dest-dir"/>
<arg value="./libs"/>
<arg value="--dest-dir"/>
<arg value="./img_src"/>
</exec> </exec>
<exec dir="." executable="../scripts/ndkbuild.sh" > <exec dir="." executable="../scripts/ndksetup.sh" output="/dev/null">
<arg value="-j3"/> <arg value="${build.target}"/>
</exec>
<exec dir=".." executable="./scripts/genvers.sh" output="ant_out.txt">
<arg value="XWords4-dbg"/>
<arg value="xw4dbg"/>
</exec> </exec>
<property name="CHAT_ENABLED" value="true" />
<property name="THUMBNAIL_ENABLED" value="true" />
<exec dir="." executable="../scripts/ndkbuild.sh" failonerror="true">
<arg value="BUILD_TARGET=${build.target}" />
<arg value="-j3"/>
<arg value="INITIAL_CLIENT_VERS=${INITIAL_CLIENT_VERS}" />
<arg value="CHAT_ENABLED=${CHAT_ENABLED}" />
<arg value="THUMBNAIL_ENABLED=${THUMBNAIL_ENABLED}" />
</exec>
<exec dir="." executable="../scripts/mkimages.sh"
failonerror="true" output="/dev/null"
/>
<exec dir="." executable="../scripts/gen_gcmid.sh"
output="src/org/eehouse/android/xw4dbg/GCMConsts.java"
failonerror="true" logError="true"
>
<arg value="xw4dbg"/>
</exec>
<exec dir=".." executable="./scripts/genvers.sh">
<arg value="XWords4-dbg"/>
<arg value="xw4dbg"/>
<arg value="${INITIAL_CLIENT_VERS}" />
<arg value="${CHAT_ENABLED}" />
<arg value="${THUMBNAIL_ENABLED}" />
</exec>
</target> </target>
<!-- <!--
<target name="-pre-compile"> <target name="-pre-compile">

View file

@ -0,0 +1,21 @@
/clear_all.svg
/search.svg
/select_all.svg
back.svg
content_copy.svg
content_discard.svg
content_new.svg
dict.svg
down.svg
download.svg
email.svg
new_group.svg
prefs.svg
relabel.svg
reset.svg
save.svg
send.svg
up.svg
clear_all.svg
search.svg
select_all.svg

View file

@ -17,3 +17,4 @@ xportwrapper.h
xptypes.h xptypes.h
xwjni.c xwjni.c
paths.h paths.h
Application.mk

View file

@ -0,0 +1,3 @@
gcm.jar
armeabi
x86

View file

@ -0,0 +1,20 @@
# To enable ProGuard in your project, edit project.properties
# to define the proguard.config property as described in that file.
#
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in ${sdk.dir}/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the ProGuard
# include property in project.properties.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View file

@ -8,4 +8,4 @@
# project structure. # project structure.
# Project target. # Project target.
target=android-7 target=android-14

View file

@ -0,0 +1,22 @@
/clear_all__gen.png
/search__gen.png
/select_all__gen.png
back__gen.png
content_copy__gen.png
content_discard__gen.png
content_edit.png
content_new__gen.png
dict__gen.png
down__gen.png
download__gen.png
email__gen.png
new_group__gen.png
prefs__gen.png
relabel__gen.png
reset__gen.png
save__gen.png
send__gen.png
up__gen.png
clear_all__gen.png
search__gen.png
select_all__gen.png

View file

@ -0,0 +1,22 @@
/clear_all__gen.png
/search__gen.png
/select_all__gen.png
back__gen.png
content_copy__gen.png
content_discard__gen.png
content_edit.png
content_new__gen.png
dict__gen.png
down__gen.png
download__gen.png
email__gen.png
new_group__gen.png
prefs__gen.png
relabel__gen.png
reset__gen.png
save__gen.png
send__gen.png
up__gen.png
clear_all__gen.png
search__gen.png
select_all__gen.png

View file

@ -0,0 +1,22 @@
/clear_all__gen.png
/search__gen.png
/select_all__gen.png
back__gen.png
content_copy__gen.png
content_discard__gen.png
content_edit.png
content_new__gen.png
dict__gen.png
down__gen.png
download__gen.png
email__gen.png
new_group__gen.png
prefs__gen.png
relabel__gen.png
reset__gen.png
save__gen.png
send__gen.png
up__gen.png
clear_all__gen.png
search__gen.png
select_all__gen.png

View file

@ -23,3 +23,7 @@ values.png
zoom.png zoom.png
bluetooth_active.png bluetooth_active.png
bluetooth_disabled.png bluetooth_disabled.png
in_arrow_active.png
in_arrow.png
out_arrow_active.png
out_arrow.png

View file

@ -0,0 +1 @@
board.xml

View file

@ -27,3 +27,8 @@ rename_game.xml
select_dialog_item.xml select_dialog_item.xml
btinviter_item.xml btinviter_item.xml
btinviter.xml btinviter.xml
confirm_sms.xml
game_list_group.xml
smsinviter_item.xml
smsinviter.xml
studylist.xml

View file

@ -0,0 +1 @@
board_menu.xml

View file

@ -3,3 +3,5 @@ chat_menu.xml
dicts_item_menu.xml dicts_item_menu.xml
games_list_item_menu.xml games_list_item_menu.xml
games_list_menu.xml games_list_menu.xml
dicts_menu.xml
studylist.xml

View file

@ -0,0 +1 @@
styles.xml

View file

@ -0,0 +1 @@
strings.xml

View file

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

View file

@ -1,28 +1,53 @@
#CrashTrack.java#
/DlgID.java
/LookupAlert.java
ABUtils.java
BTInviteActivity.java
BTReceiver.java
BTService.java
BoardActivity.java BoardActivity.java
BoardCanvas.java
BoardDims.java BoardDims.java
BoardView.java BoardView.java
BuildConstants.java
ChatActivity.java ChatActivity.java
CommsTransport.java CommsTransport.java
DbgUtils.java ConnStatusHandler.java
DBHelper.java DBHelper.java
DBUtils.java DBUtils.java
DbgUtils.java
DictBrowseActivity.java DictBrowseActivity.java
DictImportActivity.java DictImportActivity.java
DictLangCache.java DictLangCache.java
DictListPreference.java DictListPreference.java
DictsActivity.java
DictUtils.java DictUtils.java
DictsActivity.java
DispatchNotify.java DispatchNotify.java
DlgDelegate.java DlgDelegate.java
DlgState.java
EditColorPreference.java EditColorPreference.java
ExpiringDelegate.java
ExpiringLinearLayout.java
ExpiringTextView.java
FirstRunDialog.java FirstRunDialog.java
GCMConsts.java
GCMIntentService.java
GameConfig.java GameConfig.java
GameListAdapter.java GameListAdapter.java
GamesList.java GameListGroup.java
GameListItem.java
GameLock.java
GameNamer.java
GameUtils.java GameUtils.java
GamesList.java
GitVersion.java GitVersion.java
InviteActivity.java
LookupActivity.java
MountEventReceiver.java MountEventReceiver.java
MultiMsgSink.java
MultiService.java
NBSReceiver.java NBSReceiver.java
NFCUtils.java
NetLaunchInfo.java NetLaunchInfo.java
NetStateCache.java NetStateCache.java
NetUtils.java NetUtils.java
@ -35,20 +60,33 @@ RelayGameActivity.java
RelayMsgSink.java RelayMsgSink.java
RelayReceiver.java RelayReceiver.java
RelayService.java RelayService.java
SMSCheckBoxPreference.java
SMSInviteActivity.java
SMSListItem.java
SMSReceiver.java
SMSService.java
SelectableItem.java
StatusReceiver.java StatusReceiver.java
StudyList.java
ThumbCanvas.java
Toolbar.java Toolbar.java
UpdateCheckReceiver.java
Utils.java Utils.java
XWActivity.java XWActivity.java
XWApp.java XWApp.java
XWConstants.java XWConstants.java
XWEditTextPreference.java XWEditTextPreference.java
XWExpandableListActivity.java
XWListActivity.java XWListActivity.java
XWListAdapter.java XWListAdapter.java
XWListItem.java XWListItem.java
XWListPreference.java XWListPreference.java
BTInviteActivity.java XWPrefs.java
BTReceiver.java XWService.java
BTService.java XWSumListPreference.java
MultiMsgSink.java XWThumbListPreference.java
GameNamer.java DelegateBase.java
LookupActivity.java DlgID.java
GamesListActivity.java
GamesListDelegate.java
LookupAlert.java

View file

@ -0,0 +1,36 @@
/* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/*
* Copyright 2014 by Eric House (xwords@eehouse.org). All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.eehouse.android.xw4dbg;
import android.content.Context;
// This class exists solely to allow crittercism to be included in a small
// file that can be different in variants. GamesList.java is too big.
import com.crittercism.app.Crittercism;
public class CrashTrack {
public static void init( Context context ) {
if ( 0 < GCMConsts.CRITTERCISM_APP_ID.length() ) {
Crittercism.initialize(context.getApplicationContext(),
GCMConsts.CRITTERCISM_APP_ID );
}
}
}

View file

@ -15,3 +15,4 @@ TransportProcs.java
UtilCtxtImpl.java UtilCtxtImpl.java
UtilCtxt.java UtilCtxt.java
XwJNI.java XwJNI.java
BoardDims.java

View file

@ -22,7 +22,7 @@
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="68" android:versionCode="76"
android:versionName="@string/app_version" android:versionName="@string/app_version"
> >
@ -67,7 +67,7 @@
android:name=".XWApp" android:name=".XWApp"
> >
<activity android:name="GamesList" <activity android:name="GamesListActivity"
android:label="@string/app_name" android:label="@string/app_name"
android:launchMode="standard" android:launchMode="standard"
android:configChanges="keyboardHidden|orientation|screenSize" android:configChanges="keyboardHidden|orientation|screenSize"
@ -97,7 +97,7 @@
<activity android:name="SMSInviteActivity" <activity android:name="SMSInviteActivity"
android:theme="@android:style/Theme.Dialog" android:theme="@android:style/Theme.Dialog"
android:configChanges="keyboardHidden|orientation|screenSize" android:configChanges="keyboardHidden|orientation|screenSize"
android:screenOrientation="portrait" android:screenOrientation="sensor"
/> />
<activity android:name="GameConfig" <activity android:name="GameConfig"
@ -120,9 +120,8 @@
android:configChanges="keyboardHidden" android:configChanges="keyboardHidden"
/> />
<activity android:name="LookupActivity" <activity android:name="StudyListActivity"
android:configChanges="keyboardHidden|orientation|screenSize" android:configChanges="keyboardHidden|orientation|screenSize"
android:theme="@android:style/Theme.Dialog"
/> />
<receiver android:name="RelayReceiver"> <receiver android:name="RelayReceiver">

View file

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

View file

@ -0,0 +1,119 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="48"
height="48"
id="svg4020"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="clear_all.svg">
<defs
id="defs4022">
<filter
id="filter2985"
inkscape:label="Invert"
x="0"
y="0"
width="1"
height="1"
inkscape:menu="Color"
inkscape:menu-tooltip="Invert colors"
color-interpolation-filters="sRGB">
<feColorMatrix
id="feColorMatrix2987"
type="saturate"
values="1"
result="fbSourceGraphic" />
<feColorMatrix
id="feColorMatrix2989"
in="fbSourceGraphic"
values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0 " />
</filter>
<filter
id="filter2991"
inkscape:label="Invert"
x="0"
y="0"
width="1"
height="1"
inkscape:menu="Color"
inkscape:menu-tooltip="Invert colors"
color-interpolation-filters="sRGB">
<feColorMatrix
id="feColorMatrix2993"
type="saturate"
values="1"
result="fbSourceGraphic" />
<feColorMatrix
id="feColorMatrix2995"
in="fbSourceGraphic"
values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0 " />
</filter>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.6"
inkscape:cx="-19.108897"
inkscape:cy="18.800736"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:window-width="1920"
inkscape:window-height="1168"
inkscape:window-x="1600"
inkscape:window-y="0"
inkscape:window-maximized="1">
<inkscape:grid
type="xygrid"
id="grid4028"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<metadata
id="metadata4025">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1004.3622)">
<path
sodipodi:type="inkscape:offset"
inkscape:radius="0"
inkscape:original="M 345.46875 81.21875 C 344.72902 81.21875 344.58885 81.216946 344.1875 81.34375 C 343.38257 81.598067 342.58999 82.062891 342.09375 82.5625 C 341.77475 82.883678 341.3938 83.609086 341.3125 84 C 341.22298 84.429863 341.20965 85.39857 341.3125 85.875 C 341.62528 87.323718 342.67136 89.255117 344.28125 91.375 C 345.11315 92.470448 345.86052 93.350514 347.625 95.3125 C 349.88811 97.828934 350.0277 98.00649 349.78125 98.21875 C 349.71707 98.27403 348.7788 98.83901 347.71875 99.5 L 345.8125 100.71875 L 347.59375 102.3125 L 349.375 103.90625 L 349.4375 104.9375 C 349.7039 108.73495 350.42358 112.38509 351.5 115.59375 C 352.75958 119.3484 354.57923 122.63537 356.75 125.03125 C 358.60572 127.07942 360.91415 128.72525 362.34375 129 C 362.8397 129.0953 363.10304 129.10355 363.90625 129.03125 C 368.12419 128.65151 376.27662 124.92638 386.5 118.6875 C 388.86489 117.2443 389.15185 117.0443 389.09375 117 C 389.06814 116.98044 388.78792 116.87825 388.46875 116.78125 C 387.80653 116.57996 386.40432 116.0407 385.75 115.75 C 384.02903 114.98541 381.76275 113.67389 380 112.375 C 378.11737 110.98779 376.49326 109.60049 372.6875 106.09375 C 369.08179 102.77133 367.39223 101.30248 365.59375 100.03125 C 364.31686 99.128703 362.92224 98.30821 361.84375 97.8125 C 361.35492 97.587809 361.3038 97.559731 361.25 97.375 C 361.21737 97.26308 360.98011 96.434191 360.71875 95.53125 C 360.04346 93.198116 360.10511 93.38609 359.96875 93.40625 C 359.90374 93.415893 359.0438 93.746264 358.0625 94.125 C 356.70527 94.648847 356.2629 94.79153 356.1875 94.75 C 356.09406 94.698622 355.8854 94.240358 354.90625 91.9375 C 353.67009 89.030181 352.1515 86.273578 350.90625 84.65625 C 349.78011 83.193626 348.69408 82.234435 347.5625 81.6875 C 346.74383 81.29183 346.42786 81.21875 345.46875 81.21875 z "
style="opacity:0.59999999999999998;fill:#333333;fill-opacity:0.20000000000000001;fill-rule:nonzero;stroke:#221733;stroke-width:0.02301140000000000;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:0.20000000000000001;stroke-dasharray:none;filter:url(#filter2985)"
id="path3931"
d="m 345.46875,81.21875 c -0.73973,0 -0.8799,-0.0018 -1.28125,0.125 -0.80493,0.254317 -1.59751,0.719141 -2.09375,1.21875 -0.319,0.321178 -0.69995,1.046586 -0.78125,1.4375 -0.0895,0.429863 -0.10285,1.39857 0,1.875 0.31278,1.448718 1.35886,3.380117 2.96875,5.5 0.8319,1.095448 1.57927,1.975514 3.34375,3.9375 2.26311,2.516434 2.4027,2.69399 2.15625,2.90625 -0.0642,0.05528 -1.00245,0.62026 -2.0625,1.28125 l -1.90625,1.21875 1.78125,1.59375 1.78125,1.59375 0.0625,1.03125 c 0.2664,3.79745 0.98608,7.44759 2.0625,10.65625 1.25958,3.75465 3.07923,7.04162 5.25,9.4375 1.85572,2.04817 4.16415,3.694 5.59375,3.96875 0.49595,0.0953 0.75929,0.10355 1.5625,0.0312 4.21794,-0.37974 12.37037,-4.10487 22.59375,-10.34375 2.36489,-1.4432 2.65185,-1.6432 2.59375,-1.6875 -0.0256,-0.0196 -0.30583,-0.12175 -0.625,-0.21875 -0.66222,-0.20129 -2.06443,-0.74055 -2.71875,-1.03125 -1.72097,-0.76459 -3.98725,-2.07611 -5.75,-3.375 -1.88263,-1.38721 -3.50674,-2.77451 -7.3125,-6.28125 -3.60571,-3.32242 -5.29527,-4.79127 -7.09375,-6.0625 -1.27689,-0.902547 -2.67151,-1.72304 -3.75,-2.21875 -0.48883,-0.224691 -0.53995,-0.252769 -0.59375,-0.4375 -0.0326,-0.11192 -0.26989,-0.940809 -0.53125,-1.84375 -0.67529,-2.333134 -0.61364,-2.14516 -0.75,-2.125 -0.065,0.0096 -0.92495,0.340014 -1.90625,0.71875 -1.35723,0.523847 -1.7996,0.66653 -1.875,0.625 -0.0934,-0.05138 -0.3021,-0.509642 -1.28125,-2.8125 -1.23616,-2.907319 -2.75475,-5.663922 -4,-7.28125 -1.12614,-1.462624 -2.21217,-2.421815 -3.34375,-2.96875 -0.81867,-0.39567 -1.13464,-0.46875 -2.09375,-0.46875 z"
transform="matrix(1.0003125,0,0,1.0003002,-341.28439,923.18158)" />
<path
style="opacity:0.80000000000000004;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#333333;stroke-width:0.10000000000000001;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:0.20000000000000001;stroke-dasharray:none;filter:url(#filter2991)"
d="M 19.806831,47.212398 C 13.956284,44.054527 9.6791046,35.765503 8.5030398,25.306051 L 8.2105691,22.704936 6.6086002,21.230469 c -0.881083,-0.810957 -1.6019691,-1.56509 -1.6019691,-1.675852 0,-0.110762 0.7898535,-0.670628 1.7552297,-1.244147 0.9653763,-0.57352 1.819807,-1.147251 1.8987348,-1.274959 C 8.7395233,16.907803 7.518805,15.290125 5.9478882,13.440672 1.2390404,7.8969056 0.06743308,5.8467578 0.26267842,3.4923559 0.3928449,1.9227193 0.86828244,1.2604235 2.3549807,0.57772896 5.7907605,-0.9999872 9.0935267,1.5511815 12.465126,8.3871477 c 0.938221,1.9022563 1.861424,3.8279853 2.051563,4.2793973 0.407506,0.967465 0.683947,0.990565 2.738042,0.228798 l 1.515228,-0.561927 0.637974,2.013676 0.637974,2.013677 2.029396,1.166325 c 2.510496,1.44282 4.37948,2.932472 9.701285,7.732293 7.098968,6.402675 9.60378,8.151496 14.251436,9.950136 l 1.751713,0.677911 -1.372906,0.876098 C 40.506,40.529047 30.927052,45.444926 26.867443,46.791066 c -1.366943,0.45327 -3.236693,0.883603 -4.154997,0.956294 -1.468961,0.116278 -1.818201,0.05198 -2.905615,-0.534962 z"
id="path3758"
inkscape:connector-curvature="0"
transform="translate(0,1004.3622)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 8 KiB

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="120"
height="120" xml:space="preserve">
<g
id="g12"
transform="matrix(1.25,0,0,-1.25,0,120)">
<path style='fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none' d='M 29.99,72.01 78,72.01 78,11.99 29.99,11.99 29.99,72.01 z M 72,66 36,66 36,17.99 72,17.99 72,66 z M 55.34,53 42,53 42,55 55.34,55 55.34,53 z M 66,47 41.99,47 41.99,49 66,49 66,47 z M 59.34,41 42,41 42,43 59.34,43 59.34,41 z M 55.34,35 42,35 42,37 55.34,37 55.34,35 z M 64.67,28.99 41.99,28.99 41.99,30.99 64.67,30.99 64.67,28.99 z M 60.01,78.01 23.99,78.01 23.99,29.99 26.99,29.99 26.99,23.99 23.99,23.99 17.99,23.99 17.99,84.01 66,84.01 66,78.01 66,75.01 60.01,75.01 60.01,78.01 z' id='path1220'/></g>
</svg>

After

Width:  |  Height:  |  Size: 933 B

View file

@ -0,0 +1,9 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg x='0px' y='0px' xml:space='preserve' id='Layer_1' height='32px' viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg' xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' version='1.1' style='enable-background:new 0 0 32 32;' xmlns:cc='http://creativecommons.org/ns#' xmlns:dc='http://purl.org/dc/elements/1.1/' width='32px' xmlns:xlink='http://www.w3.org/1999/xlink'>
<metadata><rdf:RDF><cc:Work><dc:subject><rdf:Bag><rdf:li>core</rdf:li></rdf:Bag></dc:subject></cc:Work></rdf:RDF></metadata><path d='M26.498,23.393l-4.055-4.056c-0.357-0.356-1.003-0.322-1.65,0.015l-1.77-1.768c2.305-3.011,2.088-7.334-0.667-10.089
c-3-2.999-7.862-2.999-10.862,0c-2.998,3-2.998,7.863,0,10.862c2.756,2.755,7.079,2.973,10.09,0.667l1.769,1.768
c-0.337,0.649-0.372,1.295-0.016,1.651l4.056,4.056c0.512,0.512,1.624,0.23,2.48-0.627C26.729,25.016,27.011,23.904,26.498,23.393z
M8.637,17.215c-2.368-2.369-2.368-6.21,0-8.578c2.37-2.37,6.207-2.368,8.578,0c2.367,2.368,2.367,6.208,0,8.578
C14.844,19.583,11.004,19.583,8.637,17.215z'/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -0,0 +1,15 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg x='0px' y='0px' xml:space='preserve' id='Layer_1' height='32px' viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg' xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' version='1.1' style='enable-background:new 0 0 32 32;' xmlns:cc='http://creativecommons.org/ns#' xmlns:dc='http://purl.org/dc/elements/1.1/' width='32px' xmlns:xlink='http://www.w3.org/1999/xlink'>
<metadata><rdf:RDF><cc:Work><dc:subject><rdf:Bag><rdf:li>core</rdf:li></rdf:Bag></dc:subject></cc:Work></rdf:RDF></metadata><path d='M22.903,28h-1.257v-1.334h1.257V28z M20.393,28h-1.256v-1.334h1.256V28z
M17.883,28h-1.256v-1.334h1.256V28z M12.863,28h-1.257v-1.334h1.257V28z M10.354,28H9.097v-1.334h1.257V28z M15,23H9v-6h6V23z M4,4
h1.333v1.333H4V4z M4,6.586h1.333v1.256H4V6.586z M4,9.097h1.333v1.257H4V9.097z M4,11.606h1.333v1.257H4V11.606z M4,14.116h1.333
v1.257H4V14.116z M4,16.626h1.333v1.256H4V16.626z M4,19.137h1.333v1.256H4V19.137z M4,21.646h1.333v1.257H4V21.646z M4,24.156
h1.333v1.257H4V24.156z M4,26.666h1.333V28H4V26.666z M6.586,4h1.256v1.333H6.586V4z M6.586,26.666h1.256V28H6.586V26.666z M15,15H9
V9h6V15z M9.097,4h1.257v1.333H9.097V4z M11.606,4h1.257v1.333h-1.257V4z M14.116,4h1.257v1.333h-1.257V4z M14.116,26.666h1.257V28
h-1.257V26.666z M16.626,4h1.256v1.333h-1.256V4z M19.137,4h1.256v1.333h-1.256V4z M21.646,4h1.257v1.333h-1.257V4z M17,9h6v6h-6V9z
M17,17h6v6h-6V17z M24.156,4h1.257v1.333h-1.257V4z M24.156,26.666h1.257V28h-1.257V26.666z M26.666,4H28v1.333h-1.334V4z
M26.666,6.586H28v1.256h-1.334V6.586z M26.666,9.097H28v1.257h-1.334V9.097z M26.666,11.606H28v1.257h-1.334V11.606z
M26.666,14.116H28v1.257h-1.334V14.116z M26.666,16.626H28v1.256h-1.334V16.626z M26.666,19.137H28v1.256h-1.334V19.137z
M26.666,21.646H28v1.257h-1.334V21.646z M26.666,24.156H28v1.257h-1.334V24.156z M26.666,28v-1.334H28V28H26.666z' style='fill-rule:evenodd;clip-rule:evenodd;'/>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -67,6 +67,7 @@ COMMON_SRC_FILES += \
$(COMMON_PATH)/tray.c \ $(COMMON_PATH)/tray.c \
$(COMMON_PATH)/dictnry.c \ $(COMMON_PATH)/dictnry.c \
$(COMMON_PATH)/dictiter.c \ $(COMMON_PATH)/dictiter.c \
$(COMMON_PATH)/dictmgr.c \
$(COMMON_PATH)/mscore.c \ $(COMMON_PATH)/mscore.c \
$(COMMON_PATH)/vtabmgr.c \ $(COMMON_PATH)/vtabmgr.c \
$(COMMON_PATH)/strutils.c \ $(COMMON_PATH)/strutils.c \
@ -89,5 +90,10 @@ LOCAL_LDLIBS := -L${SYSROOT}/usr/lib -llog -lz
include $(BUILD_SHARED_LIBRARY) include $(BUILD_SHARED_LIBRARY)
ifneq ($(shell which ccache),)
TARGET_CC = ccache $(TOOLCHAIN_PREFIX)gcc
TARGET_CXX = ccache $(TOOLCHAIN_PREFIX)g++
endif
COMMON_SRC_FILES := COMMON_SRC_FILES :=
COMMON_PATH := COMMON_PATH :=

View file

@ -42,6 +42,9 @@ typedef struct _AndDictionaryCtxt {
off_t bytesSize; off_t bytesSize;
jbyte* bytes; jbyte* bytes;
jbyteArray byteArray; jbyteArray byteArray;
#ifdef DEBUG
uint32_t dbgid;
#endif
} AndDictionaryCtxt; } AndDictionaryCtxt;
#define CHECK_PTR(p,c,e) \ #define CHECK_PTR(p,c,e) \
@ -487,6 +490,7 @@ static void
and_dictionary_destroy( DictionaryCtxt* dict ) and_dictionary_destroy( DictionaryCtxt* dict )
{ {
AndDictionaryCtxt* ctxt = (AndDictionaryCtxt*)dict; AndDictionaryCtxt* ctxt = (AndDictionaryCtxt*)dict;
XP_LOGF( "%s(dict=%p); code=%x", __func__, ctxt, ctxt->dbgid );
XP_U16 nSpecials = andCountSpecials( ctxt ); XP_U16 nSpecials = andCountSpecials( ctxt );
XP_U16 ii; XP_U16 ii;
JNIEnv* env = ctxt->env; JNIEnv* env = ctxt->env;
@ -536,7 +540,10 @@ and_dictionary_destroy( DictionaryCtxt* dict )
jobject jobject
and_dictionary_getChars( JNIEnv* env, DictionaryCtxt* dict ) and_dictionary_getChars( JNIEnv* env, DictionaryCtxt* dict )
{ {
XP_ASSERT( env == ((AndDictionaryCtxt*)dict)->env ); /* XP_ASSERT( env == ((AndDictionaryCtxt*)dict)->env ); */
/* The above is failing now that dictmgr reuses dicts across threads. I
think that's ok, that I didn't have a good reason for having this
assert. But bears watching... */
/* This is cheating: specials will be rep'd as 1,2, etc. But as long as /* This is cheating: specials will be rep'd as 1,2, etc. But as long as
java code wants to ignore them anyway that's ok. Otherwise need to java code wants to ignore them anyway that's ok. Otherwise need to
@ -553,13 +560,18 @@ and_dictionary_make_empty( MPFORMAL JNIEnv* env, JNIUtilCtxt* jniutil )
= (AndDictionaryCtxt*)XP_CALLOC( mpool, sizeof( *anddict ) ); = (AndDictionaryCtxt*)XP_CALLOC( mpool, sizeof( *anddict ) );
anddict->env = env; anddict->env = env;
anddict->jniutil = jniutil; anddict->jniutil = jniutil;
#ifdef DEBUG
anddict->dbgid = rand();
#endif
dict_super_init( (DictionaryCtxt*)anddict ); dict_super_init( (DictionaryCtxt*)anddict );
MPASSIGN( anddict->super.mpool, mpool ); MPASSIGN( anddict->super.mpool, mpool );
LOG_RETURNF( "%p", anddict );
return (DictionaryCtxt*)anddict; return (DictionaryCtxt*)anddict;
} }
void void
makeDicts( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil, makeDicts( MPFORMAL JNIEnv *env, DictMgrCtxt* dictMgr, JNIUtilCtxt* jniutil,
DictionaryCtxt** dictp, PlayerDicts* dicts, DictionaryCtxt** dictp, PlayerDicts* dicts,
jobjectArray jnames, jobjectArray jdicts, jobjectArray jpaths, jobjectArray jnames, jobjectArray jdicts, jobjectArray jpaths,
jstring jlang ) jstring jlang )
@ -576,7 +588,7 @@ makeDicts( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil,
NULL : (*env)->GetObjectArrayElement( env, jpaths, ii ); NULL : (*env)->GetObjectArrayElement( env, jpaths, ii );
if ( NULL != jdict || NULL != jpath ) { if ( NULL != jdict || NULL != jpath ) {
jstring jname = (*env)->GetObjectArrayElement( env, jnames, ii ); jstring jname = (*env)->GetObjectArrayElement( env, jnames, ii );
dict = makeDict( MPPARM(mpool) env, jniutil, jname, jdict, dict = makeDict( MPPARM(mpool) env, dictMgr, jniutil, jname, jdict,
jpath, jlang, false ); jpath, jlang, false );
XP_ASSERT( !!dict ); XP_ASSERT( !!dict );
deleteLocalRefs( env, jdict, jname, DELETE_NO_REF ); deleteLocalRefs( env, jdict, jname, DELETE_NO_REF );
@ -593,13 +605,18 @@ makeDicts( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil,
} }
DictionaryCtxt* DictionaryCtxt*
makeDict( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil, jstring jname, makeDict( MPFORMAL JNIEnv *env, DictMgrCtxt* dictMgr, JNIUtilCtxt* jniutil, jstring jname,
jbyteArray jbytes, jstring jpath, jstring jlangname, jboolean check ) jbyteArray jbytes, jstring jpath, jstring jlangname, jboolean check )
{ {
jbyte* bytes = NULL; jbyte* bytes = NULL;
jbyteArray byteArray = NULL; jbyteArray byteArray = NULL;
off_t bytesSize = 0; off_t bytesSize = 0;
const char* name = (*env)->GetStringUTFChars( env, jname, NULL );
/* remember: dmgr_get calls dict_ref() */
AndDictionaryCtxt* anddict = (AndDictionaryCtxt*)dmgr_get( dictMgr, name );
if ( NULL == anddict ) {
if ( NULL == jpath ) { if ( NULL == jpath ) {
bytesSize = (*env)->GetArrayLength( env, jbytes ); bytesSize = (*env)->GetArrayLength( env, jbytes );
byteArray = (*env)->NewGlobalRef( env, jbytes ); byteArray = (*env)->NewGlobalRef( env, jbytes );
@ -623,7 +640,6 @@ makeDict( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil, jstring jname,
(*env)->ReleaseStringUTFChars( env, jpath, path ); (*env)->ReleaseStringUTFChars( env, jpath, path );
} }
AndDictionaryCtxt* anddict = NULL;
if ( NULL != bytes ) { if ( NULL != bytes ) {
anddict = (AndDictionaryCtxt*) anddict = (AndDictionaryCtxt*)
and_dictionary_make_empty( MPPARM(mpool) env, jniutil ); and_dictionary_make_empty( MPPARM(mpool) env, jniutil );
@ -634,8 +650,11 @@ makeDict( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil, jstring jname,
anddict->super.destructor = and_dictionary_destroy; anddict->super.destructor = and_dictionary_destroy;
/* copy the name */ /* copy the name */
anddict->super.name = getStringCopy( MPPARM(mpool) env, jname ); anddict->super.name = copyString( mpool, name );
anddict->super.langName = getStringCopy( MPPARM(mpool) env, jlangname ); XP_LOGF( "%s(dict=%p); code=%x; name=%s", __func__, anddict,
anddict->dbgid, anddict->super.name );
anddict->super.langName = getStringCopy( MPPARM(mpool)
env, jlangname );
XP_U32 numEdges; XP_U32 numEdges;
XP_Bool parses = parseDict( anddict, (XP_U8*)anddict->bytes, XP_Bool parses = parseDict( anddict, (XP_U8*)anddict->bytes,
@ -646,21 +665,20 @@ makeDict( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil, jstring jname,
anddict = NULL; anddict = NULL;
} }
} }
dmgr_put( dictMgr, name, &anddict->super );
dict_ref( &anddict->super );
}
return (DictionaryCtxt*)anddict; (*env)->ReleaseStringUTFChars( env, jname, name );
return &anddict->super;
} /* makeDict */ } /* makeDict */
void #ifdef DEBUG
destroyDicts( PlayerDicts* dicts ) uint32_t
andDictID( const DictionaryCtxt* dict )
{ {
int ii; const AndDictionaryCtxt* ctxt = (AndDictionaryCtxt*)dict;
DictionaryCtxt** ctxts; return ctxt->dbgid;
for ( ctxts = dicts->dicts, ii = 0;
ii < VSIZE(dicts->dicts);
++ii, ++ctxts ) {
if ( NULL != *ctxts ) {
dict_destroy( *ctxts );
}
}
} }
#endif

View file

@ -22,6 +22,7 @@
#define _ANDDICT_H_ #define _ANDDICT_H_
#include "dictnry.h" #include "dictnry.h"
#include "dictmgr.h"
#include "comtypes.h" #include "comtypes.h"
#include "jniutlswrapper.h" #include "jniutlswrapper.h"
@ -29,11 +30,11 @@ void
dict_splitFaces( DictionaryCtxt* dict, const XP_U8* bytes, dict_splitFaces( DictionaryCtxt* dict, const XP_U8* bytes,
XP_U16 nBytes, XP_U16 nFaces ); XP_U16 nBytes, XP_U16 nFaces );
DictionaryCtxt* makeDict( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil, DictionaryCtxt* makeDict( MPFORMAL JNIEnv *env, DictMgrCtxt* dictMgr,
jstring jname, jbyteArray bytes, jstring path, JNIUtilCtxt* jniutil, jstring jname, jbyteArray bytes,
jstring jlang, jboolean check ); jstring path, jstring jlang, jboolean check );
void makeDicts( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil, void makeDicts( MPFORMAL JNIEnv *env, DictMgrCtxt* dictMgr, JNIUtilCtxt* jniutil,
DictionaryCtxt** dict, PlayerDicts* dicts, jobjectArray jnames, DictionaryCtxt** dict, PlayerDicts* dicts, jobjectArray jnames,
jobjectArray jdicts, jobjectArray jpaths, jstring jlang ); jobjectArray jdicts, jobjectArray jpaths, jstring jlang );
@ -44,4 +45,8 @@ DictionaryCtxt* and_dictionary_make_empty( MPFORMAL JNIEnv *env,
jobject and_dictionary_getChars( JNIEnv* env, DictionaryCtxt* dict ); jobject and_dictionary_getChars( JNIEnv* env, DictionaryCtxt* dict );
# ifdef DEBUG
uint32_t andDictID(const DictionaryCtxt* dict);
# endif
#endif #endif

View file

@ -20,6 +20,7 @@
#include "drawwrapper.h" #include "drawwrapper.h"
#include "andutils.h" #include "andutils.h"
#include "anddict.h"
#include "paths.h" #include "paths.h"
enum { enum {
@ -517,6 +518,7 @@ static void
and_draw_dictChanged( DrawCtx* dctx, XP_S16 playerNum, and_draw_dictChanged( DrawCtx* dctx, XP_S16 playerNum,
const DictionaryCtxt* dict ) const DictionaryCtxt* dict )
{ {
XP_LOGF( "%s(dict=%p); code=%x", __func__, dict, andDictID(dict) );
AndDraw* draw = (AndDraw*)dctx; AndDraw* draw = (AndDraw*)dctx;
if ( NULL != draw->jdraw ) { if ( NULL != draw->jdraw ) {
XP_LangCode code = 0; /* A null dict means no-lang */ XP_LangCode code = 0; /* A null dict means no-lang */
@ -528,6 +530,14 @@ and_draw_dictChanged( DrawCtx* dctx, XP_S16 playerNum,
draw->curLang = code; draw->curLang = code;
DRAW_CBK_HEADER( "dictChanged", "(I)V" ); DRAW_CBK_HEADER( "dictChanged", "(I)V" );
/* /\* create a DictWrapper object -- if the API changes to require it *\/ */
/* jclass rclass = (*env)->FindClass( env, PKG_PATH("jni/XwJNI$DictWrapper") ); */
/* // http://stackoverflow.com/questions/7260376/how-to-create-an-object-with-jni */
/* const char* sig = "(L" PKG_PATH("jni/XwJNI") ";I)V"; */
/* jmethodID initId = (*env)->GetMethodID( env, rclass, "<init>", sig ); */
/* jobject jdict = (*env)->NewObject( env, rclass, initId, (int)dict ); */
(*env)->CallVoidMethod( env, draw->jdraw, mid, (jint)dict ); (*env)->CallVoidMethod( env, draw->jdraw, mid, (jint)dict );
} }
} }

View file

@ -392,8 +392,10 @@ and_util_makeEmptyDict( XW_UtilCtxt* uc )
#else #else
AndGlobals* globals = (AndGlobals*)uc->closure; AndGlobals* globals = (AndGlobals*)uc->closure;
AndUtil* andutil = (AndUtil*)uc; AndUtil* andutil = (AndUtil*)uc;
return and_dictionary_make_empty( MPPARM( ((AndUtil*)uc)->util.mpool ) DictionaryCtxt* result =
and_dictionary_make_empty( MPPARM( ((AndUtil*)uc)->util.mpool )
*andutil->env, globals->jniutil ); *andutil->env, globals->jniutil );
return dict_ref( result );
#endif #endif
} }

View file

@ -28,11 +28,11 @@
typedef unsigned char XP_U8; typedef unsigned char XP_U8;
typedef signed char XP_S8; typedef signed char XP_S8;
typedef unsigned short XP_U16; typedef uint16_t XP_U16;
typedef signed short XP_S16; typedef int16_t XP_S16;
typedef unsigned long XP_U32; typedef uint32_t XP_U32;
typedef signed long XP_S32; typedef int32_t XP_S32;
typedef char XP_UCHAR; typedef char XP_UCHAR;
@ -46,7 +46,7 @@ typedef XP_U32 XP_Time;
#define XP_S "%s" #define XP_S "%s"
#define XP_P "%p" #define XP_P "%p"
#define XP_CR "\n" #define XP_CR "\n"
#define XP_LD "%ld" #define XP_LD "%d"
# define XP_RANDOM() rand() # define XP_RANDOM() rand()

View file

@ -30,6 +30,7 @@
#include "strutils.h" #include "strutils.h"
#include "dictnry.h" #include "dictnry.h"
#include "dictiter.h" #include "dictiter.h"
#include "dictmgr.h"
#include "utilwrapper.h" #include "utilwrapper.h"
#include "drawwrapper.h" #include "drawwrapper.h"
@ -39,6 +40,45 @@
#include "jniutlswrapper.h" #include "jniutlswrapper.h"
#include "paths.h" #include "paths.h"
/* Globals for the whole game */
typedef struct _JNIGlobalState {
JNIEnv* env;
DictMgrCtxt* dictMgr;
MPSLOT
} JNIGlobalState;
JNIEXPORT jint JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_initGlobals
( JNIEnv* env, jclass C )
{
#ifdef MEM_DEBUG
MemPoolCtx* mpool = mpool_make();
#endif
JNIGlobalState* state = (JNIGlobalState*)XP_CALLOC( mpool, sizeof(*state) );
state->env = env;
state->dictMgr = dmgr_make( MPPARM_NOCOMMA( mpool ) );
MPASSIGN( state->mpool, mpool );
LOG_RETURNF( "%p", state );
return (jint)state;
}
JNIEXPORT void JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_cleanGlobals
( JNIEnv* env, jclass C, jint ptr )
{
LOG_FUNC();
if ( 0 != ptr ) {
JNIGlobalState* state = (JNIGlobalState*)ptr;
XP_ASSERT( state->env == env );
dmgr_destroy( state->dictMgr );
#ifdef MEM_DEBUG
MemPoolCtx* mpool = state->mpool;
#endif
XP_FREE( mpool, state );
mpool_destroy( mpool );
}
}
static const SetInfo gi_ints[] = { static const SetInfo gi_ints[] = {
ARR_MEMBER( CurGameInfo, nPlayers ) ARR_MEMBER( CurGameInfo, nPlayers )
,ARR_MEMBER( CurGameInfo, gameSeconds ) ,ARR_MEMBER( CurGameInfo, gameSeconds )
@ -316,18 +356,36 @@ Java_org_eehouse_android_xw4_jni_XwJNI_comms_1getUUID
return jstr; return jstr;
} }
JNIEXPORT void JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1ref
( JNIEnv* env, jclass C, jint dictPtr )
{
if ( 0 != dictPtr ) {
DictionaryCtxt* dict = (DictionaryCtxt*)dictPtr;
dict_ref( dict );
}
}
JNIEXPORT void JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1unref
( JNIEnv* env, jclass C, jint dictPtr )
{
if ( 0 != dictPtr ) {
DictionaryCtxt* dict = (DictionaryCtxt*)dictPtr;
dict_unref( dict );
}
}
JNIEXPORT jboolean JNICALL JNIEXPORT jboolean JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1getInfo Java_org_eehouse_android_xw4_jni_XwJNI_dict_1getInfo
( JNIEnv* env, jclass C, jbyteArray jDictBytes, jstring jname, jstring jpath, ( JNIEnv* env, jclass C, jint jniGlobalPtr, jbyteArray jDictBytes,
jobject jniu, jboolean check, jobject jinfo ) jstring jname, jstring jpath, jobject jniu, jboolean check, jobject jinfo )
{ {
jboolean result = false; jboolean result = false;
#ifdef MEM_DEBUG JNIGlobalState* state = (JNIGlobalState*)jniGlobalPtr;
MemPoolCtx* mpool = mpool_make(); JNIUtilCtxt* jniutil = makeJNIUtil( MPPARM(state->mpool) &env, jniu );
#endif DictionaryCtxt* dict = makeDict( MPPARM(state->mpool) env, state->dictMgr,
JNIUtilCtxt* jniutil = makeJNIUtil( MPPARM(mpool) &env, jniu ); jniutil, jname, jDictBytes, jpath, NULL, check );
DictionaryCtxt* dict = makeDict( MPPARM(mpool) env, jniutil, jname,
jDictBytes, jpath, NULL, check );
if ( NULL != dict ) { if ( NULL != dict ) {
if ( NULL != jinfo ) { if ( NULL != jinfo ) {
XP_LangCode code = dict_getLangCode( dict ); XP_LangCode code = dict_getLangCode( dict );
@ -336,14 +394,11 @@ Java_org_eehouse_android_xw4_jni_XwJNI_dict_1getInfo
setInt( env, jinfo, "wordCount", dict_getWordCount( dict ) ); setInt( env, jinfo, "wordCount", dict_getWordCount( dict ) );
setString( env, jinfo, "md5Sum", dict_getMd5Sum( dict ) ); setString( env, jinfo, "md5Sum", dict_getMd5Sum( dict ) );
} }
dict_destroy( dict ); dict_unref( dict );
result = true; result = true;
} }
destroyJNIUtil( &jniutil ); destroyJNIUtil( &jniutil );
#ifdef MEM_DEBUG
mpool_destroy( mpool );
#endif
return result; return result;
} }
@ -380,6 +435,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_dict_1getTileValue
typedef struct _JNIState { typedef struct _JNIState {
XWGame game; XWGame game;
JNIEnv* env; JNIEnv* env;
JNIGlobalState* globalJNI;
AndGlobals globals; AndGlobals globals;
XP_U16 curSaveCount; XP_U16 curSaveCount;
XP_U16 lastSavedSize; XP_U16 lastSavedSize;
@ -422,22 +478,24 @@ typedef struct _JNIState {
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_initJNI Java_org_eehouse_android_xw4_jni_XwJNI_initJNI
( JNIEnv* env, jclass C ) ( JNIEnv* env, jclass C, int jniGlobalPtr )
{ {
struct timeval tv; /* Why am I doing this twice? */
gettimeofday( &tv, NULL ); /* struct timeval tv; */
srandom( tv.tv_sec ); /* gettimeofday( &tv, NULL ); */
/* srandom( tv.tv_sec ); */
#ifdef MEM_DEBUG #ifdef MEM_DEBUG
MemPoolCtx* mpool = mpool_make(); MemPoolCtx* mpool = mpool_make();
#endif #endif
JNIState* state = (JNIState*)XP_CALLOC( mpool, sizeof(*state) ); JNIState* state = (JNIState*)XP_CALLOC( mpool, sizeof(*state) );
state->globalJNI = (JNIGlobalState*)jniGlobalPtr;
AndGlobals* globals = &state->globals; AndGlobals* globals = &state->globals;
globals->state = (struct JNIState*)state; globals->state = (struct JNIState*)state;
MPASSIGN( state->mpool, mpool ); MPASSIGN( state->mpool, mpool );
globals->vtMgr = make_vtablemgr(MPPARM_NOCOMMA(mpool)); globals->vtMgr = make_vtablemgr(MPPARM_NOCOMMA(mpool));
XP_U32 secs = getCurSeconds( env ); XP_U32 secs = getCurSeconds( env );
XP_LOGF( "initing srand with %ld", secs ); XP_LOGF( "initing srand with %d", secs );
srandom( secs ); srandom( secs );
return (jint) state; return (jint) state;
@ -471,8 +529,10 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeNewGame
DictionaryCtxt* dict; DictionaryCtxt* dict;
PlayerDicts dicts; PlayerDicts dicts;
makeDicts( MPPARM(mpool) env, globals->jniutil, &dict, &dicts, j_names,
j_dicts, j_paths, j_lang ); makeDicts( MPPARM(state->globalJNI->mpool) env, state->globalJNI->dictMgr,
globals->jniutil, &dict, &dicts, j_names, j_dicts,
j_paths, j_lang );
#ifdef STUBBED_DICT #ifdef STUBBED_DICT
if ( !dict ) { if ( !dict ) {
XP_LOGF( "falling back to stubbed dict" ); XP_LOGF( "falling back to stubbed dict" );
@ -480,7 +540,9 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeNewGame
} }
#endif #endif
model_setDictionary( state->game.model, dict ); model_setDictionary( state->game.model, dict );
dict_unref( dict ); /* game owns it now */
model_setPlayerDicts( state->game.model, &dicts ); model_setPlayerDicts( state->game.model, &dicts );
dict_unref_all( &dicts );
XWJNI_END(); XWJNI_END();
} /* makeNewGame */ } /* makeNewGame */
@ -526,8 +588,9 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeFromStream
globals->util = makeUtil( MPPARM(mpool) &state->env, globals->util = makeUtil( MPPARM(mpool) &state->env,
jutil, globals->gi, globals ); jutil, globals->gi, globals );
globals->jniutil = makeJNIUtil( MPPARM(mpool) &state->env, jniu ); globals->jniutil = makeJNIUtil( MPPARM(mpool) &state->env, jniu );
makeDicts( MPPARM(mpool) env, globals->jniutil, &dict, &dicts, jdictNames, makeDicts( MPPARM(state->globalJNI->mpool) env, state->globalJNI->dictMgr,
jdicts, jpaths, jlang ); globals->jniutil, &dict, &dicts, jdictNames, jdicts, jpaths,
jlang );
if ( !!jdraw ) { if ( !!jdraw ) {
globals->dctx = makeDraw( MPPARM(mpool) &state->env, jdraw ); globals->dctx = makeDraw( MPPARM(mpool) &state->env, jdraw );
} }
@ -543,6 +606,8 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeFromStream
globals->util, globals->dctx, &cp, globals->util, globals->dctx, &cp,
globals->xportProcs ); globals->xportProcs );
stream_destroy( stream ); stream_destroy( stream );
dict_unref( dict ); /* game owns it now */
dict_unref_all( &dicts );
if ( result ) { if ( result ) {
XP_ASSERT( 0 != globals->gi->gameID ); XP_ASSERT( 0 != globals->gi->gameID );
@ -552,10 +617,6 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeFromStream
} else { } else {
destroyDraw( &globals->dctx ); destroyDraw( &globals->dctx );
destroyXportProcs( &globals->xportProcs ); destroyXportProcs( &globals->xportProcs );
destroyDicts( &dicts );
if ( NULL != dict ) {
dict_destroy( dict );
}
destroyUtil( &globals->util ); destroyUtil( &globals->util );
destroyJNIUtil( &globals->jniutil ); destroyJNIUtil( &globals->jniutil );
destroyGI( MPPARM(mpool) &globals->gi ); destroyGI( MPPARM(mpool) &globals->gi );
@ -1278,6 +1339,8 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1summarize
setInt( env, jsummary, "seed", comms_getChannelSeed( comms ) ); setInt( env, jsummary, "seed", comms_getChannelSeed( comms ) );
setInt( env, jsummary, "missingPlayers", setInt( env, jsummary, "missingPlayers",
server_getMissingPlayers( state->game.server ) ); server_getMissingPlayers( state->game.server ) );
setInt( env, jsummary, "nPacketsPending",
comms_countPendingPackets( state->game.comms ) );
if ( COMMS_CONN_RELAY == addr.conType ) { if ( COMMS_CONN_RELAY == addr.conType ) {
XP_UCHAR buf[128]; XP_UCHAR buf[128];
XP_U16 len = VSIZE(buf); XP_U16 len = VSIZE(buf);
@ -1405,6 +1468,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1getGi
static const SetInfo gsi_ints[] = { static const SetInfo gsi_ints[] = {
ARR_MEMBER( GameStateInfo, visTileCount ), ARR_MEMBER( GameStateInfo, visTileCount ),
ARR_MEMBER( GameStateInfo, nPendingMessages ),
ARR_MEMBER( GameStateInfo, trayVisState ), ARR_MEMBER( GameStateInfo, trayVisState ),
}; };
static const SetInfo gsi_bools[] = { static const SetInfo gsi_bools[] = {
@ -1452,9 +1516,12 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1changeDict
jbyteArray jDictBytes, jstring jpath ) jbyteArray jDictBytes, jstring jpath )
{ {
XWJNI_START_GLOBALS(); XWJNI_START_GLOBALS();
DictionaryCtxt* dict = makeDict( MPPARM(mpool) env, globals->jniutil, DictionaryCtxt* dict = makeDict( MPPARM(state->globalJNI->mpool) env,
jname, jDictBytes, jpath, NULL, false ); state->globalJNI->dictMgr,
globals->jniutil, jname, jDictBytes,
jpath, NULL, false );
game_changeDict( MPPARM(mpool) &state->game, globals->gi, dict ); game_changeDict( MPPARM(mpool) &state->game, globals->gi, dict );
dict_unref( dict );
setJGI( env, jgi, globals->gi ); setJGI( env, jgi, globals->gi );
XWJNI_END(); XWJNI_END();
return XP_FALSE; /* no need to redraw */ return XP_FALSE; /* no need to redraw */
@ -1510,6 +1577,25 @@ Java_org_eehouse_android_xw4_jni_XwJNI_comms_1isConnected
return result; return result;
} }
JNIEXPORT jstring JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_comms_1getStats
( JNIEnv* env, jclass C, jint gamePtr )
{
jstring result = NULL;
#ifdef DEBUG
XWJNI_START_GLOBALS();
if ( NULL != state->game.comms ) {
XWStreamCtxt* stream = mem_stream_make( MPPARM(mpool) globals->vtMgr,
NULL, 0, NULL );
comms_getStats( state->game.comms, stream );
result = streamToJString( env, stream );
stream_destroy( stream );
}
XWJNI_END();
#endif
return result;
}
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_server_1endGame Java_org_eehouse_android_xw4_jni_XwJNI_server_1endGame
( JNIEnv* env, jclass C, jint gamePtr ) ( JNIEnv* env, jclass C, jint gamePtr )
@ -1554,33 +1640,29 @@ typedef struct _DictIterData {
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1init Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1init
( JNIEnv* env, jclass C, jbyteArray jDictBytes, jstring jname, ( JNIEnv* env, jclass C, jint jniGlobalPtr, jbyteArray jDictBytes, jstring jname,
jstring jpath, jobject jniu ) jstring jpath, jobject jniu )
{ {
jint closure = 0; jint closure = 0;
#ifdef MEM_DEBUG JNIGlobalState* state = (JNIGlobalState*)jniGlobalPtr;
MemPoolCtx* mpool = mpool_make(); DictIterData* data = XP_CALLOC( state->mpool, sizeof(*data) );
#endif
DictIterData* data = XP_CALLOC( mpool, sizeof(*data) );
data->env = env; data->env = env;
JNIUtilCtxt* jniutil = makeJNIUtil( MPPARM(mpool) &data->env, jniu ); JNIUtilCtxt* jniutil = makeJNIUtil( MPPARM(state->mpool) &data->env, jniu );
DictionaryCtxt* dict = makeDict( MPPARM(mpool) env, jniutil, jname, DictionaryCtxt* dict = makeDict( MPPARM(state->mpool) env, state->dictMgr,
jDictBytes, jpath, NULL, false ); jniutil, jname, jDictBytes, jpath, NULL,
false );
if ( !!dict ) { if ( !!dict ) {
data->vtMgr = make_vtablemgr( MPPARM_NOCOMMA(mpool) ); data->vtMgr = make_vtablemgr( MPPARM_NOCOMMA(state->mpool) );
data->jniutil = jniutil; data->jniutil = jniutil;
data->dict = dict; data->dict = dict;
data->depth = 2; data->depth = 2;
#ifdef MEM_DEBUG #ifdef MEM_DEBUG
data->mpool = mpool; data->mpool = state->mpool;
#endif #endif
closure = (int)data; closure = (int)data;
} else { } else {
destroyJNIUtil( &jniutil ); destroyJNIUtil( &jniutil );
XP_FREE( mpool, data ); XP_FREE( state->mpool, data );
#ifdef MEM_DEBUG
mpool_destroy( mpool );
#endif
} }
return closure; return closure;
} }
@ -1651,14 +1733,11 @@ Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1destroy
#ifdef MEM_DEBUG #ifdef MEM_DEBUG
MemPoolCtx* mpool = data->mpool; MemPoolCtx* mpool = data->mpool;
#endif #endif
dict_destroy( data->dict ); dict_unref( data->dict );
destroyJNIUtil( &data->jniutil ); destroyJNIUtil( &data->jniutil );
freeIndices( data ); freeIndices( data );
vtmgr_destroy( MPPARM(mpool) data->vtMgr ); vtmgr_destroy( MPPARM(mpool) data->vtMgr );
XP_FREE( mpool, data ); XP_FREE( mpool, data );
#ifdef MEM_DEBUG
mpool_destroy( mpool );
#endif
} }
} }

View file

@ -11,4 +11,4 @@
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target. # Project target.
target=Google Inc.:Google APIs:14 target=android-14

View file

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

View file

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

View file

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

View file

@ -13,6 +13,12 @@
android:background="@android:drawable/list_selector_background" android:background="@android:drawable/list_selector_background"
> >
<CheckBox android:id="@+id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
/>
<TextView android:id="@+id/text_item" <TextView android:id="@+id/text_item"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View file

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <org.eehouse.android.xw4.LookupAlert
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:orientation="vertical"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_height="fill_parent"
@ -19,9 +20,13 @@
android:layout_weight="1" android:layout_weight="1"
/> />
<Button android:id="@+id/button_study"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<Button android:id="@+id/button_done" <Button android:id="@+id/button_done"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
/> />
</LinearLayout> </org.eehouse.android.xw4.LookupAlert>

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingLeft="8dp"
android:paddingRight="8dp"
>
<LinearLayout android:id="@+id/pick_lang"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<TextView android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/study_langpick"
/>
<Spinner android:id="@+id/pick_lang_spinner"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:drawSelectorOnTop="true"
/>
</LinearLayout>
<ListView android:id="@id/android:list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:drawSelectorOnTop="false"
/>
</LinearLayout>

View file

@ -81,6 +81,10 @@
</menu> </menu>
</item> </item>
<item android:id="@+id/games_menu_study"
android:title="@string/gamel_menu_study"
/>
<item android:id="@+id/gamel_menu_checkmoves" <item android:id="@+id/gamel_menu_checkmoves"
android:title="@string/gamel_menu_checkmoves" android:title="@string/gamel_menu_checkmoves"
/> />
@ -94,4 +98,7 @@
android:alphabeticShortcut="A" android:alphabeticShortcut="A"
/> />
<item android:id="@+id/board_menu_game_netstats"
android:title="@string/board_menu_game_netstats" />
</menu> </menu>

View file

@ -58,6 +58,10 @@
</menu> </menu>
</item> </item>
<item android:id="@+id/games_menu_study"
android:title="@string/gamel_menu_study"
/>
<item android:id="@+id/gamel_menu_checkmoves" <item android:id="@+id/gamel_menu_checkmoves"
android:title="@string/gamel_menu_checkmoves" android:title="@string/gamel_menu_checkmoves"
/> />
@ -71,4 +75,7 @@
android:alphabeticShortcut="A" android:alphabeticShortcut="A"
/> />
<item android:id="@+id/board_menu_game_netstats"
android:title="@string/board_menu_game_netstats" />
</menu> </menu>

View file

@ -16,11 +16,19 @@
android:icon="@drawable/prefs__gen" android:icon="@drawable/prefs__gen"
android:showAsAction="ifRoom" android:showAsAction="ifRoom"
/> />
<item android:id="@+id/games_menu_rateme"
android:title="@string/menu_rateme"
/>
<item android:id="@+id/games_menu_dicts" <item android:id="@+id/games_menu_dicts"
android:title="@string/gamel_menu_dicts" android:title="@string/gamel_menu_dicts"
android:icon="@drawable/dict__gen" android:icon="@drawable/dict__gen"
android:showAsAction="ifRoom" android:showAsAction="ifRoom"
/> />
<item android:id="@+id/games_menu_study"
android:title="@string/gamel_menu_study"
/>
<item android:id="@+id/games_menu_email" <item android:id="@+id/games_menu_email"
android:title="@string/board_menu_file_email" android:title="@string/board_menu_file_email"
android:icon="@drawable/email__gen" android:icon="@drawable/email__gen"
@ -30,6 +38,9 @@
android:title="@string/board_menu_file_about" android:title="@string/board_menu_file_about"
android:icon="@android:drawable/ic_menu_info_details" android:icon="@android:drawable/ic_menu_info_details"
/> />
<item android:id="@+id/games_menu_resend"
android:title="@string/board_menu_game_resend"
/>
<item android:id="@+id/games_menu_checkmoves" <item android:id="@+id/games_menu_checkmoves"
android:title="@string/gamel_menu_checkmoves" android:title="@string/gamel_menu_checkmoves"
android:icon="@drawable/stat_notify_sync" android:icon="@drawable/stat_notify_sync"

View file

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/slmenu_lookup_sel"
android:icon="@drawable/search__gen"
android:showAsAction="ifRoom"
/>
<item android:id="@+id/slmenu_select_all"
android:title="@string/slmenu_select_all"
android:icon="@drawable/select_all__gen"
android:showAsAction="ifRoom"
/>
<item android:id="@+id/slmenu_deselect_all"
android:title="@string/slmenu_deselect_all"
android:icon="@drawable/clear_all__gen"
android:showAsAction="ifRoom"
/>
<item android:id="@+id/slmenu_copy_sel"
android:title="@string/slmenu_copy_sel"
android:icon="@drawable/content_copy__gen"
android:showAsAction="ifRoom"
/>
<item android:id="@+id/slmenu_clear_sel"
android:title="@string/slmenu_clear_sel"
android:icon="@drawable/content_discard__gen"
android:showAsAction="ifRoom"
/>
</menu>

View file

@ -5,46 +5,19 @@
</style> </style>
</head> </head>
<body> <body>
<b>Crosswords 4.4 beta 76 release</b> <b>Crosswords 4.4 beta 83 release</b>
<p>(Betas 74 through 76 fix bugs but add nothing new, so the previous
notes remain in place.)</p>
<p>Beta 73 adds two new features, snapshots of in-progress games
displayed as part of the main Games List screen, and the ability to
send invitations by tapping your device against the one you want to
invite (using &quot;Near Field Communication&quot;, or NFC, which
Google brands &quot;Android beaming&quot;.)</p>
<p>Both features are optional. NFC is off by default, so you have to
enable it via Google's system Preferences app. And snapshots, while
on by default, can be disabled (or resized to better fit your
screen) in Crosswords' App Preferences section under
Appearances.</p>
<h3>New with this release</h3> <h3>New with this release</h3>
<ul> <ul>
<li>Add thumbnails of board to main screen</li> <li>Display board in upside-down portrait orientation too (where OS version allows)</li>
<li>Add ability to invite via NFC</li> <li>Bug fix (obscure): don't mangle unicode model names</li>
<li>Use Actionbar and select/act pattern on Wordlist Browser
screen</li>
<li>Highlight most recently opened game in Games List screen by
default </li>
<li>Disable SMS on KitKat (Android 4.4) devices: Google&apos;s
broken some behavior it depended on</li>
<li>Disable hiding title bar on devices with Action Bar or without a
menu key</li>
<li>Make tile borders thicker when selected in trade mode</li>
<li>Refuse to create more than one game from an invitation</li>
<li>Add the.freedictionary.com lookup for German words</li>
<li>Fix disappearing games bug</li>
<li>Fix wordlist crasher (Thanks BM!)</li>
</ul> </ul>
<h3>Next up</h3> <h3>Next up</h3>
<ul> <ul>
<li>Much better support for localization</li>
<li>Look, again, at play via Bluetooth now that HTC phones aren't quite so common</li>
<li>Fix SMS play for KitKat</li> <li>Fix SMS play for KitKat</li>
<li>Use Actionbar and select/act pattern on more screens</li>
<li>Offer "Rematch" when game's over</li> <li>Offer "Rematch" when game's over</li>
</ul> </ul>

View file

@ -182,7 +182,7 @@
<string name="msg_dup_room">Un altre amfitrió ha registrat una sala amb aquest nom. Canvieu el nom a la vostra o intentenu més tard.</string> <string name="msg_dup_room">Un altre amfitrió ha registrat una sala amb aquest nom. Canvieu el nom a la vostra o intentenu més tard.</string>
<string name="msg_lost_other">El repetidor ha perdut el contacte amb algun altre dispositiu durant aquesta partida.</string> <string name="msg_lost_other">El repetidor ha perdut el contacte amb algun altre dispositiu durant aquesta partida.</string>
<string name="ids_badwords">Les paraules %s no es troben al diccionari.</string> <string name="ids_badwordsf">Les paraules %s no es troben al diccionari.</string>
<string name="badwords_accept"> Voleu acceptar aquesta jugada?</string> <string name="badwords_accept"> Voleu acceptar aquesta jugada?</string>
<string name="badwords_lost"> Torn perdut.</string> <string name="badwords_lost"> Torn perdut.</string>
<string name="badwords_title">Les paraules no són vàlides</string> <string name="badwords_title">Les paraules no són vàlides</string>

View file

@ -161,7 +161,7 @@
<string name="msg_dup_room">Jiný server si již zaregistroval místnost s tímto jménem. Přejmenujte ji nebo to zkuste později.</string> <string name="msg_dup_room">Jiný server si již zaregistroval místnost s tímto jménem. Přejmenujte ji nebo to zkuste později.</string>
<string name="msg_lost_other">Relay ztratil kontakt s nějakým zařízením ve hře.</string> <string name="msg_lost_other">Relay ztratil kontakt s nějakým zařízením ve hře.</string>
<string name="ids_badwords">Slovo[a] %s nebylo nalezeno ve slovníku.</string> <string name="ids_badwordsf">Slovo[a] %s nebylo nalezeno ve slovníku.</string>
<string name="badwords_accept"> Chcete přesto přijmout tento tah?</string> <string name="badwords_accept"> Chcete přesto přijmout tento tah?</string>
<string name="badwords_lost"> Tah ztracen.</string> <string name="badwords_lost"> Tah ztracen.</string>
<string name="badwords_title">Neplatné slovo[a]</string> <string name="badwords_title">Neplatné slovo[a]</string>

View file

@ -157,12 +157,6 @@
list_item_rename) --> list_item_rename) -->
<string name="rename_label">Mudar o nome desse jogo para:</string> <string name="rename_label">Mudar o nome desse jogo para:</string>
<!-- Text of confirmation dialog posted when list_item_reset menu
is selected -->
<string name="confirm_reset">Você tem certeza que quer reiniciar
esse jogo? Reiniciar apaga todas as jogadas e informações de
conexão.</string>
<!-- <!--
############################################################ ############################################################
# :Screens: # :Screens:
@ -605,7 +599,7 @@
phonies_disallow is the current setting and a "phony" is phonies_disallow is the current setting and a "phony" is
played. One of the two following strings will be appended played. One of the two following strings will be appended
--> -->
<string name="ids_badwords">Palavra(s) %1$s não encontrada(s) na <string name="ids_badwordsf">Palavra(s) %1$s não encontrada(s) na
lista de palavras %2$s.</string> lista de palavras %2$s.</string>
<!-- Appended to the above in the phonies_warn case. User may <!-- Appended to the above in the phonies_warn case. User may
@ -2144,11 +2138,6 @@
<string name="group_cur_games">Meus jogos</string> <string name="group_cur_games">Meus jogos</string>
<string name="group_new_games">Novos jogos</string> <string name="group_new_games">Novos jogos</string>
<string name="group_confirm_del">Você tem certeza que quer apagar
esse grupo?</string>
<string name="group_confirm_delf">\u0020(Ele contém %d jogo(s),
que também serão apagados.)</string>
<string name="rename_group_label">Mudar o nome desse grupo para:</string> <string name="rename_group_label">Mudar o nome desse grupo para:</string>
<string name="game_name_group_title">Nomear grupo</string> <string name="game_name_group_title">Nomear grupo</string>

View file

@ -161,7 +161,7 @@
<string name="msg_dup_room">Iný server si už zaregistroval miestnosť s týmto menom. Premenujte ju alebo to skúste neskôr.</string> <string name="msg_dup_room">Iný server si už zaregistroval miestnosť s týmto menom. Premenujte ju alebo to skúste neskôr.</string>
<string name="msg_lost_other">Relay stratil kontakt s niektorým zariadením v hre.</string> <string name="msg_lost_other">Relay stratil kontakt s niektorým zariadením v hre.</string>
<string name="ids_badwords">Slovo[á] %s nebolo nájdené v slovníku.</string> <string name="ids_badwordsf">Slovo[á] %s nebolo nájdené v slovníku.</string>
<string name="badwords_accept"> Chcete napriek tomu potvrdiť tento ťah?</string> <string name="badwords_accept"> Chcete napriek tomu potvrdiť tento ťah?</string>
<string name="badwords_lost"> Ťah stratený.</string> <string name="badwords_lost"> Ťah stratený.</string>
<string name="badwords_title">Neplatné slovo[á]</string> <string name="badwords_title">Neplatné slovo[á]</string>

View file

@ -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 76</string> <string name="app_version">4.4 beta 83</string>
</resources> </resources>

View file

@ -59,6 +59,7 @@
<string name="key_enable_sms">key_enable_sms</string> <string name="key_enable_sms">key_enable_sms</string>
<string name="key_keep_screenon">key_keep_screenon</string> <string name="key_keep_screenon">key_keep_screenon</string>
<string name="key_thumbsize">key_thumbsize3</string> <string name="key_thumbsize">key_thumbsize3</string>
<string name="key_studyon">key_studyon</string>
<string name="key_summary_field">key_summary_field</string> <string name="key_summary_field">key_summary_field</string>
<string name="key_default_loc">key_default_loc</string> <string name="key_default_loc">key_default_loc</string>
@ -107,6 +108,7 @@
<string name="key_na_browse">key_na_browse</string> <string name="key_na_browse">key_na_browse</string>
<string name="key_na_browseall">key_na_browseall</string> <string name="key_na_browseall">key_na_browseall</string>
<string name="key_na_values">key_na_values</string> <string name="key_na_values">key_na_values</string>
<string name="key_na_studycopy">key_na_studycopy</string>
<string name="key_enable_debug">key_enable_debug</string> <string name="key_enable_debug">key_enable_debug</string>
<string name="key_enable_dup_invite">key_enable_dup_invite</string> <string name="key_enable_dup_invite">key_enable_dup_invite</string>
<string name="key_download_path">key_download_path</string> <string name="key_download_path">key_download_path</string>
@ -122,6 +124,7 @@
<string name="invite_mime">application/x-xwordsinvite</string> <string name="invite_mime">application/x-xwordsinvite</string>
<string name="game_summary_field_rowid">rowid</string> <string name="game_summary_field_rowid">rowid</string>
<string name="game_summary_field_gameid">gameid</string> <string name="game_summary_field_gameid">gameid</string>
<string name="game_summary_field_npackets">Pending packet count</string>
<!--string name="invite_mime">text/plain</string--> <!--string name="invite_mime">text/plain</string-->
<string name="dict_url">http://eehouse.org/and_wordlists</string> <string name="dict_url">http://eehouse.org/and_wordlists</string>
@ -141,6 +144,8 @@
only)</string> only)</string>
<string name="title_send_data_sms">Send SMS as data</string> <string name="title_send_data_sms">Send SMS as data</string>
<string name="summary_send_data_sms">(fails on CDMA phones)</string> <string name="summary_send_data_sms">(fails on CDMA phones)</string>
<string name="board_menu_game_netstats">Network stats</string>
<string name="netstats_title">Game network stats</string>
<string name="git_rev_title">Source version id</string> <string name="git_rev_title">Source version id</string>
<string name="relay_port">Relay game port</string> <string name="relay_port">Relay game port</string>

View file

@ -159,8 +159,8 @@
<!-- Text of confirmation dialog posted when list_item_reset menu <!-- Text of confirmation dialog posted when list_item_reset menu
is selected --> is selected -->
<string name="confirm_reset">Are you sure you want to reset the <string name="confirm_resetf">Are you sure you want to reset the %d
selected game[s]? (Resetting erases all moves and any connection selected game[s]?\n\n(Resetting erases all moves and any connection
information.)</string> information.)</string>
<!-- <!--
@ -601,7 +601,7 @@
phonies_disallow is the current setting and a "phony" is phonies_disallow is the current setting and a "phony" is
played. One of the two following strings will be appended played. One of the two following strings will be appended
--> -->
<string name="ids_badwords">Word[s] %1$s not found in <string name="ids_badwordsf">Word[s] %1$s not found in
wordlist %2$s.</string> wordlist %2$s.</string>
<!-- Appended to the above in the phonies_warn case. User may <!-- Appended to the above in the phonies_warn case. User may
@ -674,6 +674,7 @@
able to remove this from non-debug versions of the game able to remove this from non-debug versions of the game
because users should not have to do do this EVER. --> because users should not have to do do this EVER. -->
<string name="board_menu_game_resend">Resend messages</string> <string name="board_menu_game_resend">Resend messages</string>
<string name="resend_finishedf">Resend finished; sent %d message[s].</string>
<!-- <!--
############################################################ ############################################################
@ -1757,9 +1758,9 @@
--> -->
<!-- String giving version info, which is substituted in. --> <!-- String giving version info, which is substituted in. -->
<string name="about_versf">Crosswords for Android, Version %1$s, <string name="about_versf">Crosswords for Android, Version %1$s,
rev %2$s.</string> rev %2$s, built on %3$s.</string>
<!-- copyright info --> <!-- copyright info -->
<string name="about_copyright">Copyright (C) 1998-2013 by Eric <string name="about_copyright">Copyright (C) 1998-2014 by Eric
House. This free/open source software is released under the GNU Public House. This free/open source software is released under the GNU Public
License.</string> License.</string>
@ -1788,10 +1789,13 @@
<!-- New strings that need to be documented and found a home <!-- New strings that need to be documented and found a home
above. --> above. -->
<string name="button_lookup">Look up words</string> <string name="button_lookup">Look up words</string>
<string name="button_lookup_study">Look up/study words</string>
<!-- --> <!-- -->
<string name="button_lookupf">Look up %s</string> <string name="button_lookupf">Look up %s</string>
<string name="button_lookup_studyf">Look up/study %s</string>
<!-- --> <!-- -->
<string name="title_lookup">Tap to look up</string> <string name="title_lookup">Tap to look up</string>
<string name="title_lookup_study">Tap to look up or study</string>
<!-- --> <!-- -->
<string name="button_done">Done</string> <string name="button_done">Done</string>
<!-- --> <!-- -->
@ -2119,14 +2123,10 @@
<string name="group_cur_games">My games</string> <string name="group_cur_games">My games</string>
<string name="group_new_games">New games</string> <string name="group_new_games">New games</string>
<string name="group_confirm_del">Are you sure you want to delete <string name="groups_confirm_delf">Are you sure you want to delete
the selected group?</string> the %d selected group[s]?</string>
<string name="groups_confirm_del">Are you sure you want to delete <string name="groups_confirm_del_gamesf">\n\n(%d game[s] will
the selected groups?</string> also be deleted.)</string>
<string name="group_confirm_delf">\u0020(It contains %d game[s],
which will also be deleted.)</string>
<string name="groups_confirm_delf">\u0020(They contains %d game[s],
which will also be deleted.)</string>
<string name="rename_group_label">Change the name of this group to:</string> <string name="rename_group_label">Change the name of this group to:</string>
<string name="game_name_group_title">Name group</string> <string name="game_name_group_title">Name group</string>
@ -2167,13 +2167,12 @@
<string name="sel_groupsf">Groups: %d</string> <string name="sel_groupsf">Groups: %d</string>
<string name="summary_thumbsize">Thumbnail size</string> <string name="summary_thumbsize">Thumbnail size</string>
<string name="thumb_off">Disabled</string> <string name="thumb_off">Disabled</string>
<string name="sel_dictsf">Wordlists: %d</string>
<!-- <string name="summary_thumb_enabled">Display snapshots of games</string> --> <!-- <string name="summary_thumb_enabled">Display snapshots of games</string> -->
<string name="dropped_dupe">Invitation received but ignored: it <string name="dropped_dupe">Invitation received but ignored: it
has already been used to create a game.</string> has already been used to create a game.</string>
<string name="cur_menu_markerf">%1$s (yours)</string> <string name="cur_menu_markerf">%1$s (in use)</string>
<string name="board_menu_invite">Invite</string> <string name="board_menu_invite">Invite</string>
<string name="enable_nfc">NFC is turned off on this device. You <string name="enable_nfc">NFC is turned off on this device. You
@ -2197,4 +2196,39 @@
browsers for viewing the wordlists downloads page, DO NOT choose browsers for viewing the wordlists downloads page, DO NOT choose
Firefox. Some versions have a bug that can cause the wordlists to Firefox. Some versions have a bug that can cause the wordlists to
be lost.</string> be lost.</string>
<string name="menu_rateme">Rate Crosswords</string>
<string name="no_market">Google Play app not found</string>
<string name="add_to_studyf">Add %s to studylist</string>
<string name="title_studyon">Enable studylists</string>
<string name="summary_studyon">Offer to add to and display lists
of words to remember</string>
<string name="gamel_menu_study">Studylist…</string>
<string name="slmenu_copy_sel">Copy to clipboard</string>
<string name="slmenu_clear_sel">Delete</string>
<string name="confirm_studylist_clearf">Are you sure you want to
delete the %d selected word[s]?\n\n(This action cannot be undone.)</string>
<string name="paste_donef">%d word[s] copied</string>
<string name="add_donef">%s added to list</string>
<string name="studylist_titlef">Studylist for %s</string>
<string name="study_langpick">Your words for:</string>
<string name="study_no_langf">You have not yet saved any words
into a studylist for %s.</string>
<string name="study_no_lists">You have not yet saved any words
into a studylist.</string>
<string name="not_again_studycopy">The selected words will be
copied to the system clipboard. You can then paste them into any
app that supports pasting text, e.g. an email app.</string>
<string name="lookup_title">Word lookup</string>
<string name="slmenu_select_all">Select all</string>
<string name="slmenu_deselect_all">Unselect all</string>
<string name="sel_itemsf">Selected: %d</string>
</resources> </resources>

View file

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

View file

@ -246,6 +246,11 @@
android:summary="@string/summary_sort_tiles" android:summary="@string/summary_sort_tiles"
android:defaultValue="true" android:defaultValue="true"
/> />
<CheckBoxPreference android:key="@string/key_studyon"
android:title="@string/title_studyon"
android:summary="@string/summary_studyon"
android:defaultValue="true"
/>
<CheckBoxPreference android:key="@string/key_ringer_zoom" <CheckBoxPreference android:key="@string/key_ringer_zoom"
android:title="@string/ringer_zoom" android:title="@string/ringer_zoom"
android:summary="@string/ringer_zoom_summary" android:summary="@string/ringer_zoom_summary"

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/* /*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved. * rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/* /*
* Copyright 2009-2011 by Eric House (xwords@eehouse.org). All * Copyright 2009-2011 by Eric House (xwords@eehouse.org). All
* rights reserved. * rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/* /*
* Copyright 2012 by Eric House (xwords@eehouse.org). All rights * Copyright 2012 by Eric House (xwords@eehouse.org). All rights
* reserved. * reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/* /*
* Copyright 2010 - 2012 by Eric House (xwords@eehouse.org). All * Copyright 2010 - 2012 by Eric House (xwords@eehouse.org). All
* rights reserved. * rights reserved.
@ -481,7 +481,7 @@ public class BTService extends XWService {
host.getAddress() ); host.getAddress() );
for ( long rowid : rowids ) { for ( long rowid : rowids ) {
if ( BoardActivity.feedMessage( gameID, buffer, addr ) ) { if ( BoardDelegate.feedMessage( gameID, buffer, addr ) ) {
// do nothing // do nothing
} else if ( haveGame && } else if ( haveGame &&
GameUtils.feedMessage( BTService.this, rowid, GameUtils.feedMessage( BTService.this, rowid,
@ -968,7 +968,7 @@ public class BTService extends XWService {
private void postNotification( int gameID, int title, String body, private void postNotification( int gameID, int title, String body,
long rowid ) long rowid )
{ {
Intent intent = GamesList.makeGameIDIntent( this, gameID ); Intent intent = GamesListActivity.makeGameIDIntent( this, gameID );
Utils.postNotification( this, intent, R.string.new_btmove_title, Utils.postNotification( this, intent, R.string.new_btmove_title,
body, (int)rowid ); body, (int)rowid );
} }
@ -1018,12 +1018,6 @@ public class BTService extends XWService {
} }
return sent; return sent;
} }
public boolean relayNoConnProc( byte[] buf, String relayID )
{
Assert.fail();
return false;
}
} }
} }

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/* /*
* Copyright 2009 - 2013 by Eric House (xwords@eehouse.org). All * Copyright 2009 - 2013 by Eric House (xwords@eehouse.org). All
* rights reserved. * rights reserved.
@ -38,6 +38,7 @@ import org.eehouse.android.xw4.jni.DrawCtx;
import org.eehouse.android.xw4.jni.DrawScoreInfo; import org.eehouse.android.xw4.jni.DrawScoreInfo;
import org.eehouse.android.xw4.jni.JNIThread; import org.eehouse.android.xw4.jni.JNIThread;
import org.eehouse.android.xw4.jni.XwJNI; import org.eehouse.android.xw4.jni.XwJNI;
import org.eehouse.android.xw4.jni.XwJNI.DictWrapper;
import junit.framework.Assert; import junit.framework.Assert;
@ -84,7 +85,7 @@ public class BoardCanvas extends Canvas implements DrawCtx {
private Drawable m_downArrow; private Drawable m_downArrow;
private int m_trayOwner = -1; private int m_trayOwner = -1;
private int m_pendingScore; private int m_pendingScore;
private int m_dictPtr = 0; private DictWrapper m_dict;
protected String[] m_dictChars; protected String[] m_dictChars;
private boolean m_hasSmallScreen; private boolean m_hasSmallScreen;
private int m_backgroundUsed = 0x00000000; private int m_backgroundUsed = 0x00000000;
@ -142,6 +143,7 @@ public class BoardCanvas extends Canvas implements DrawCtx {
m_activity = activity; m_activity = activity;
m_bitmap = bitmap; m_bitmap = bitmap;
m_jniThread = jniThread; m_jniThread = jniThread;
m_dict = new DictWrapper();
m_hasSmallScreen = Utils.hasSmallScreen( m_context ); m_hasSmallScreen = Utils.hasSmallScreen( m_context );
@ -542,20 +544,21 @@ public class BoardCanvas extends Canvas implements DrawCtx {
} }
} }
public void dictChanged( final int dictPtr ) public void dictChanged( final int newPtr )
{ {
if ( m_dictPtr != dictPtr ) { int curPtr = m_dict.getDictPtr();
if ( 0 == dictPtr ) { if ( curPtr != newPtr ) {
if ( 0 == newPtr ) {
m_fontDims = null; m_fontDims = null;
m_dictChars = null; m_dictChars = null;
} else if ( m_dictPtr == 0 || } else if ( 0 == curPtr
!XwJNI.dict_tilesAreSame( m_dictPtr, dictPtr ) ) { || !XwJNI.dict_tilesAreSame( curPtr, newPtr ) ) {
m_fontDims = null; m_fontDims = null;
m_dictChars = null; m_dictChars = null;
m_activity.runOnUiThread( new Runnable() { m_activity.runOnUiThread( new Runnable() {
public void run() { public void run() {
if ( null != m_jniThread ) { if ( null != m_jniThread ) {
m_dictChars = XwJNI.dict_getChars( dictPtr ); m_dictChars = XwJNI.dict_getChars( newPtr );
// draw again // draw again
m_jniThread.handle( JNIThread.JNICmd m_jniThread.handle( JNIThread.JNICmd
.CMD_INVALALL ); .CMD_INVALALL );
@ -563,7 +566,8 @@ public class BoardCanvas extends Canvas implements DrawCtx {
} }
}); });
} }
m_dictPtr = dictPtr; m_dict.release();
m_dict = new DictWrapper( newPtr );
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/* /*
* Copyright 2009 - 2012 by Eric House (xwords@eehouse.org). All * Copyright 2009 - 2012 by Eric House (xwords@eehouse.org). All
* rights reserved. * rights reserved.
@ -20,6 +20,7 @@
package org.eehouse.android.xw4; package org.eehouse.android.xw4;
import android.app.Activity;
import android.view.View; import android.view.View;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Paint; import android.graphics.Paint;
@ -51,13 +52,14 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
private Context m_context; private Context m_context;
private int m_defaultFontHt; private int m_defaultFontHt;
private int m_mediumFontHt; private int m_mediumFontHt;
private Runnable m_invalidator;
private int m_jniGamePtr; private int m_jniGamePtr;
private CurGameInfo m_gi; private CurGameInfo m_gi;
private int m_layoutWidth; private int m_layoutWidth;
private int m_layoutHeight; private int m_layoutHeight;
private BoardCanvas m_canvas; // owns the bitmap private BoardCanvas m_canvas; // owns the bitmap
private JNIThread m_jniThread; private JNIThread m_jniThread;
private XWActivity m_parent; private Activity m_parent;
private boolean m_measuredFromDims = false; private boolean m_measuredFromDims = false;
private BoardDims m_dims; private BoardDims m_dims;
private CommsAddrRec.CommsConnType m_connType = private CommsAddrRec.CommsConnType m_connType =
@ -76,6 +78,11 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
final float scale = getResources().getDisplayMetrics().density; final float scale = getResources().getDisplayMetrics().density;
m_defaultFontHt = (int)(MIN_FONT_DIPS * scale + 0.5f); m_defaultFontHt = (int)(MIN_FONT_DIPS * scale + 0.5f);
m_mediumFontHt = m_defaultFontHt * 3 / 2; m_mediumFontHt = m_defaultFontHt * 3 / 2;
m_invalidator = new Runnable() {
public void run() {
invalidate();
}
};
} }
@Override @Override
@ -203,6 +210,8 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
// nothing to do // nothing to do
} else if ( null == m_gi ) { } else if ( null == m_gi ) {
// nothing to do either // nothing to do either
} else if ( null == m_jniThread ) {
// nothing to do either
} else if ( null == m_dims ) { } else if ( null == m_dims ) {
// m_canvas = null; // m_canvas = null;
// need to synchronize?? // need to synchronize??
@ -249,7 +258,7 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
} // layoutBoardOnce } // layoutBoardOnce
// BoardHandler interface implementation // BoardHandler interface implementation
public void startHandling( XWActivity parent, JNIThread thread, public void startHandling( Activity parent, JNIThread thread,
int gamePtr, CurGameInfo gi, int gamePtr, CurGameInfo gi,
CommsAddrRec.CommsConnType connType ) CommsAddrRec.CommsConnType connType )
{ {
@ -291,11 +300,7 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
} }
// Force update now that we have bits to copy // Force update now that we have bits to copy
m_parent.runOnUiThread( new Runnable() { m_parent.runOnUiThread( m_invalidator );
public void run() {
invalidate();
}
});
} }
public void dimsChanged( BoardDims dims ) public void dimsChanged( BoardDims dims )

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/* /*
* Copyright 2011 by Eric House (xwords@eehouse.org). All rights * Copyright 2011 by Eric House (xwords@eehouse.org). All rights
* reserved. * reserved.
@ -33,9 +33,9 @@ import android.view.MenuItem;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.widget.LinearLayout; import android.widget.LinearLayout;
public class ChatActivity extends XWActivity implements View.OnClickListener { public class ChatActivity extends Activity {
private long m_rowid; private ChatDelegate m_dlgt;
@Override @Override
public void onCreate( Bundle savedInstanceState ) public void onCreate( Bundle savedInstanceState )
@ -45,33 +45,7 @@ public class ChatActivity extends XWActivity implements View.OnClickListener {
setContentView( R.layout.chat ); setContentView( R.layout.chat );
m_rowid = getIntent().getLongExtra( GameUtils.INTENT_KEY_ROWID, -1 ); m_dlgt = new ChatDelegate( this, savedInstanceState );
DBUtils.HistoryPair[] pairs = DBUtils.getChatHistory( this, m_rowid );
if ( null != pairs ) {
LinearLayout layout = (LinearLayout)
findViewById( R.id.chat_history );
LayoutInflater factory = LayoutInflater.from( this );
for ( DBUtils.HistoryPair pair : pairs ) {
TextView view = (TextView)factory
.inflate( pair.sourceLocal
? R.layout.chat_history_local
: R.layout.chat_history_remote,
null );
view.setText( pair.msg );
layout.addView( view );
}
}
((Button)findViewById( R.id.send_button ))
.setOnClickListener( this );
setTitle( getString( R.string.chat_titlef,
GameUtils.getName( this, m_rowid ) ) );
} else {
// Should really assert....
finish();
} }
} }
@ -86,33 +60,7 @@ public class ChatActivity extends XWActivity implements View.OnClickListener {
@Override @Override
public boolean onOptionsItemSelected( MenuItem item ) public boolean onOptionsItemSelected( MenuItem item )
{ {
boolean handled = R.id.chat_menu_clear == item.getItemId(); return m_dlgt.onOptionsItemSelected( item )
if ( handled ) { || super.onOptionsItemSelected( item );
DBUtils.clearChatHistory( this, m_rowid );
LinearLayout layout =
(LinearLayout)findViewById( R.id.chat_history );
layout.removeAllViews();
} else {
handled = super.onOptionsItemSelected( item );
} }
return handled;
}
@Override
public void onClick( View view )
{
EditText edit = (EditText)findViewById( R.id.chat_edit );
String text = edit.getText().toString();
if ( null == text || text.length() == 0 ) {
setResult( Activity.RESULT_CANCELED );
} else {
DBUtils.appendChatHistory( this, m_rowid, text, true );
Intent result = new Intent();
result.putExtra( BoardActivity.INTENT_KEY_CHAT, text );
setResult( Activity.RESULT_OK, result );
}
finish();
}
} }

View file

@ -0,0 +1,112 @@
/* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/*
* Copyright 2011 by Eric House (xwords@eehouse.org). All rights
* reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.eehouse.android.xw4;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MenuInflater;
import android.widget.LinearLayout;
public class ChatDelegate extends DelegateBase
implements View.OnClickListener {
private long m_rowid;
private Activity m_activity;
public ChatDelegate( Activity activity, Bundle savedInstanceState )
{
super( activity, savedInstanceState );
m_activity = activity;
init( savedInstanceState );
}
private void init( Bundle savedInstanceState )
{
if ( BuildConstants.CHAT_SUPPORTED ) {
m_rowid = m_activity.getIntent().getLongExtra( GameUtils.INTENT_KEY_ROWID, -1 );
DBUtils.HistoryPair[] pairs = DBUtils.getChatHistory( m_activity, m_rowid );
if ( null != pairs ) {
LinearLayout layout = (LinearLayout)
m_activity.findViewById( R.id.chat_history );
LayoutInflater factory = LayoutInflater.from( m_activity );
for ( DBUtils.HistoryPair pair : pairs ) {
TextView view = (TextView)factory
.inflate( pair.sourceLocal
? R.layout.chat_history_local
: R.layout.chat_history_remote,
null );
view.setText( pair.msg );
layout.addView( view );
}
}
((Button)m_activity.findViewById( R.id.send_button ))
.setOnClickListener( this );
String title =
m_activity.getString( R.string.chat_titlef,
GameUtils.getName( m_activity, m_rowid ) );
m_activity.setTitle( title );
} else {
// Should really assert....
m_activity.finish();
}
}
protected boolean onOptionsItemSelected( MenuItem item )
{
boolean handled = R.id.chat_menu_clear == item.getItemId();
if ( handled ) {
DBUtils.clearChatHistory( m_activity, m_rowid );
LinearLayout layout =
(LinearLayout)m_activity.findViewById( R.id.chat_history );
layout.removeAllViews();
}
return handled;
}
public void onClick( View view )
{
EditText edit = (EditText)m_activity.findViewById( R.id.chat_edit );
String text = edit.getText().toString();
if ( null == text || text.length() == 0 ) {
m_activity.setResult( Activity.RESULT_CANCELED );
} else {
DBUtils.appendChatHistory( m_activity, m_rowid, text, true );
Intent result = new Intent();
result.putExtra( BoardDelegate.INTENT_KEY_CHAT, text );
m_activity.setResult( Activity.RESULT_OK, result );
}
m_activity.finish();
}
}

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/* /*
* Copyright 2009 - 2012 by Eric House (xwords@eehouse.org). All * Copyright 2009 - 2012 by Eric House (xwords@eehouse.org). All
* rights reserved. * rights reserved.
@ -387,11 +387,8 @@ public class CommsTransport implements TransportProcs,
m_relayAddr = new CommsAddrRec( addr ); m_relayAddr = new CommsAddrRec( addr );
} }
switch ( addr.conType ) { if ( !XWApp.UDP_ENABLED
case COMMS_CONN_RELAY: && CommsConnType.COMMS_CONN_RELAY == addr.conType ) {
if ( XWApp.UDP_ENABLED ) {
nSent = RelayService.sendPacket( m_context, m_rowid, buf );
} else {
if ( NetStateCache.netAvail( m_context ) ) { if ( NetStateCache.netAvail( m_context ) ) {
putOut( buf ); // add to queue putOut( buf ); // add to queue
if ( null == m_thread ) { if ( null == m_thread ) {
@ -400,19 +397,8 @@ public class CommsTransport implements TransportProcs,
} }
nSent = buf.length; nSent = buf.length;
} }
} } else {
break; nSent = sendForAddr( m_context, addr, m_rowid, gameID, buf );
case COMMS_CONN_SMS:
nSent = SMSService.sendPacket( m_context, addr.sms_phone,
gameID, buf );
break;
case COMMS_CONN_BT:
nSent = BTService.enqueueFor( m_context, buf, addr.bt_hostName,
addr.bt_btAddr, gameID );
break;
default:
Assert.fail();
break;
} }
// Keep this while debugging why the resend_all that gets // Keep this while debugging why the resend_all that gets
@ -468,6 +454,30 @@ public class CommsTransport implements TransportProcs,
return false; return false;
} }
public static int sendForAddr( Context context, CommsAddrRec addr,
long rowID, int gameID, byte[] buf )
{
int nSent = -1;
switch ( addr.conType ) {
case COMMS_CONN_RELAY:
Assert.assertTrue( XWApp.UDP_ENABLED );
nSent = RelayService.sendPacket( context, rowID, buf );
break;
case COMMS_CONN_SMS:
nSent = SMSService.sendPacket( context, addr.sms_phone,
gameID, buf );
break;
case COMMS_CONN_BT:
nSent = BTService.enqueueFor( context, buf, addr.bt_hostName,
addr.bt_btAddr, gameID );
break;
default:
Assert.fail();
break;
}
return nSent;
}
/* NPEs in m_selector calls: sometimes my Moment gets into a state /* NPEs in m_selector calls: sometimes my Moment gets into a state
* where after 15 or so seconds of Crosswords trying to connect to * where after 15 or so seconds of Crosswords trying to connect to
* the relay I get a crash. Logs show it's inside one or both of * the relay I get a crash. Logs show it's inside one or both of
@ -477,5 +487,4 @@ public class CommsTransport implements TransportProcs,
* perhaps catch NPEs here just to be safe. But then do what? * perhaps catch NPEs here just to be safe. But then do what?
* Tell user to restart device? * Tell user to restart device?
*/ */
} }

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/* /*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved. * rights reserved.
@ -237,7 +237,7 @@ public class ConnStatusHandler {
updateStatusImpl( context, cbacks, connType, success, false ); updateStatusImpl( context, cbacks, connType, success, false );
} }
public static void updateStatusImpl( Context context, ConnStatusCBacks cbacks, private static void updateStatusImpl( Context context, ConnStatusCBacks cbacks,
CommsConnType connType, boolean success, CommsConnType connType, boolean success,
boolean isIn ) boolean isIn )
{ {

View file

@ -0,0 +1,27 @@
/* -*- compile-command: "find-and-ant.sh 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;
public class CrashTrack {
public static void init( Context context ) {} // does nothing here
}

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/* /*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved. * rights reserved.
@ -36,8 +36,9 @@ public class DBHelper extends SQLiteOpenHelper {
public static final String TABLE_NAME_DICTBROWSE = "dictbrowse"; public static final String TABLE_NAME_DICTBROWSE = "dictbrowse";
public static final String TABLE_NAME_DICTINFO = "dictinfo"; public static final String TABLE_NAME_DICTINFO = "dictinfo";
public static final String TABLE_NAME_GROUPS = "groups"; public static final String TABLE_NAME_GROUPS = "groups";
public static final String TABLE_NAME_STUDYLIST = "study";
private static final String DB_NAME = "xwdb"; private static final String DB_NAME = "xwdb";
private static final int DB_VERSION = 18; private static final int DB_VERSION = 20;
public static final String GAME_NAME = "GAME_NAME"; public static final String GAME_NAME = "GAME_NAME";
public static final String VISID = "VISID"; public static final String VISID = "VISID";
@ -69,6 +70,7 @@ public class DBHelper extends SQLiteOpenHelper {
public static final String SMSPHONE = "SMSPHONE"; // unused -- so far 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";
public static final String NPACKETSPENDING = "NPACKETSPENDING";
public static final String DICTNAME = "DICTNAME"; public static final String DICTNAME = "DICTNAME";
public static final String MD5SUM = "MD5SUM"; public static final String MD5SUM = "MD5SUM";
@ -87,6 +89,9 @@ public class DBHelper extends SQLiteOpenHelper {
public static final String GROUPNAME = "GROUPNAME"; public static final String GROUPNAME = "GROUPNAME";
public static final String EXPANDED = "EXPANDED"; public static final String EXPANDED = "EXPANDED";
public static final String WORD = "WORD";
public static final String LANGUAGE = "LANGUAGE";
private Context m_context; private Context m_context;
private static final String[][] s_summaryColsAndTypes = { private static final String[][] s_summaryColsAndTypes = {
@ -120,6 +125,7 @@ public class DBHelper extends SQLiteOpenHelper {
,{ CONTRACTED, "INTEGER DEFAULT 0" } ,{ CONTRACTED, "INTEGER DEFAULT 0" }
,{ CREATE_TIME, "INTEGER" } ,{ CREATE_TIME, "INTEGER" }
,{ LASTPLAY_TIME,"INTEGER" } ,{ LASTPLAY_TIME,"INTEGER" }
,{ NPACKETSPENDING,"INTEGER" }
,{ SNAPSHOT, "BLOB" } ,{ SNAPSHOT, "BLOB" }
,{ THUMBNAIL, "BLOB" } ,{ THUMBNAIL, "BLOB" }
}; };
@ -153,6 +159,12 @@ public class DBHelper extends SQLiteOpenHelper {
,{ EXPANDED, "INTEGER(1)" } ,{ EXPANDED, "INTEGER(1)" }
}; };
private static final String[][] s_studySchema = {
{ WORD, "TEXT" }
,{ LANGUAGE, "INTEGER(1)" }
,{ "UNIQUE", "(" + WORD + ", " + LANGUAGE + ")" }
};
public DBHelper( Context context ) public DBHelper( Context context )
{ {
super( context, DB_NAME, null, DB_VERSION ); super( context, DB_NAME, null, DB_VERSION );
@ -172,7 +184,8 @@ public class DBHelper extends SQLiteOpenHelper {
createTable( db, TABLE_NAME_DICTINFO, s_dictInfoColsAndTypes ); createTable( db, TABLE_NAME_DICTINFO, s_dictInfoColsAndTypes );
createTable( db, TABLE_NAME_DICTBROWSE, s_dictBrowseColsAndTypes ); createTable( db, TABLE_NAME_DICTBROWSE, s_dictBrowseColsAndTypes );
forceRowidHigh( db, TABLE_NAME_SUM ); forceRowidHigh( db, TABLE_NAME_SUM );
createGroupsTable( db ); createGroupsTable( db, false );
createStudyTable( db );
} }
@Override @Override
@ -181,6 +194,7 @@ public class DBHelper extends SQLiteOpenHelper {
{ {
DbgUtils.logf( "onUpgrade: old: %d; new: %d", oldVersion, newVersion ); DbgUtils.logf( "onUpgrade: old: %d; new: %d", oldVersion, newVersion );
boolean madeSumTable = false;
switch( oldVersion ) { switch( oldVersion ) {
case 5: case 5:
createTable( db, TABLE_NAME_OBITS, s_obitsColsAndTypes ); createTable( db, TABLE_NAME_OBITS, s_obitsColsAndTypes );
@ -206,16 +220,26 @@ public class DBHelper extends SQLiteOpenHelper {
addSumColumn( db, LASTMOVE ); addSumColumn( db, LASTMOVE );
case 14: case 14:
addSumColumn( db, GROUPID ); addSumColumn( db, GROUPID );
createGroupsTable( db ); createGroupsTable( db, true );
case 15: case 15:
moveToCurGames( db ); moveToCurGames( db );
case 16: case 16:
addSumColumn( db, VISID ); addSumColumn( db, VISID );
setColumnsEqual( db, TABLE_NAME_SUM, VISID, "rowid" ); setColumnsEqual( db, TABLE_NAME_SUM, VISID, "rowid" );
makeAutoincrement( db, TABLE_NAME_SUM, s_summaryColsAndTypes ); makeAutoincrement( db, TABLE_NAME_SUM, s_summaryColsAndTypes );
madeSumTable = true;
case 17: case 17:
if ( !madeSumTable ) {
// THUMBNAIL also added by makeAutoincrement above
addSumColumn( db, THUMBNAIL ); addSumColumn( db, THUMBNAIL );
// nothing yet }
case 18:
createStudyTable( db );
case 19:
if ( !madeSumTable ) {
// NPACKETSPENDING also added by makeAutoincrement above
addSumColumn( db, NPACKETSPENDING );
}
break; break;
default: default:
db.execSQL( "DROP TABLE " + TABLE_NAME_SUM + ";" ); db.execSQL( "DROP TABLE " + TABLE_NAME_SUM + ";" );
@ -256,28 +280,40 @@ public class DBHelper extends SQLiteOpenHelper {
db.execSQL( query.toString() ); db.execSQL( query.toString() );
} }
private void createGroupsTable( SQLiteDatabase db ) private void createGroupsTable( SQLiteDatabase db, boolean isUpgrade )
{ {
// Do we have any existing games we'll be grouping?
if ( isUpgrade ) {
isUpgrade = 0 < countGames( db );
}
createTable( db, TABLE_NAME_GROUPS, s_groupsSchema ); createTable( db, TABLE_NAME_GROUPS, s_groupsSchema );
// Create an empty group name // Create an empty group name
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
if ( isUpgrade ) {
values.put( GROUPNAME, m_context.getString(R.string.group_cur_games) ); values.put( GROUPNAME, m_context.getString(R.string.group_cur_games) );
values.put( EXPANDED, 1 ); values.put( EXPANDED, 1 );
long curGroup = db.insert( TABLE_NAME_GROUPS, null, values ); long curGroup = db.insert( TABLE_NAME_GROUPS, null, values );
values = new ContentValues();
values.put( GROUPNAME, m_context.getString(R.string.group_new_games) );
values.put( EXPANDED, 1 );
long newGroup = db.insert( TABLE_NAME_GROUPS, null, values );
// place all existing games in the initial unnamed group // place all existing games in the initial unnamed group
values = new ContentValues(); values = new ContentValues();
values.put( GROUPID, curGroup ); values.put( GROUPID, curGroup );
db.update( DBHelper.TABLE_NAME_SUM, values, null, null ); db.update( DBHelper.TABLE_NAME_SUM, values, null, null );
}
values = new ContentValues();
values.put( GROUPNAME, m_context.getString(R.string.group_new_games) );
values.put( EXPANDED, 1 );
long newGroup = db.insert( TABLE_NAME_GROUPS, null, values );
XWPrefs.setDefaultNewGameGroup( m_context, newGroup ); XWPrefs.setDefaultNewGameGroup( m_context, newGroup );
} }
private void createStudyTable( SQLiteDatabase db )
{
createTable( db, TABLE_NAME_STUDYLIST, s_studySchema );
}
// Move all existing games to the row previously named "cur games' // Move all existing games to the row previously named "cur games'
private void moveToCurGames( SQLiteDatabase db ) private void moveToCurGames( SQLiteDatabase db )
{ {
@ -362,4 +398,16 @@ public class DBHelper extends SQLiteOpenHelper {
query = String.format( "DELETE FROM %s", name ); query = String.format( "DELETE FROM %s", name );
db.execSQL( query ); db.execSQL( query );
} }
private int countGames( SQLiteDatabase db )
{
final String query = "SELECT COUNT(*) FROM " + TABLE_NAME_SUM;
Cursor cursor = db.rawQuery( query, null );
cursor.moveToFirst();
int result = cursor.getInt(0);
cursor.close();
return result;
}
} }

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/* /*
* Copyright 2009 - 2012 by Eric House (xwords@eehouse.org). All * Copyright 2009 - 2012 by Eric House (xwords@eehouse.org). All
* rights reserved. * rights reserved.
@ -50,6 +50,7 @@ import java.util.StringTokenizer;
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.CommsAddrRec.CommsConnType;
import org.eehouse.android.xw4.DictUtils.DictLoc; import org.eehouse.android.xw4.DictUtils.DictLoc;
@ -135,7 +136,7 @@ public class DBUtils {
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,
DBHelper.LASTMOVE DBHelper.LASTMOVE, DBHelper.NPACKETSPENDING
}; };
String selection = String.format( ROW_ID_FMT, lock.getRowid() ); String selection = String.format( ROW_ID_FMT, lock.getRowid() );
@ -202,13 +203,18 @@ public class DBUtils {
summary.scores = scores; summary.scores = scores;
int col = cursor.getColumnIndex( DBHelper.CONTYPE ); int col = cursor.getColumnIndex( DBHelper.CONTYPE );
if ( col >= 0 ) { if ( 0 <= col ) {
tmp = cursor.getInt( col ); tmp = cursor.getInt( col );
summary.conType = CommsAddrRec.CommsConnType.values()[tmp]; summary.conType = CommsAddrRec.CommsConnType.values()[tmp];
col = cursor.getColumnIndex( DBHelper.SEED ); col = cursor.getColumnIndex( DBHelper.SEED );
if ( col >= 0 ) { if ( 0 < col ) {
summary.seed = cursor.getInt( col ); summary.seed = cursor.getInt( col );
} }
col = cursor.getColumnIndex( DBHelper.NPACKETSPENDING );
if ( 0 <= col ) {
summary.nPacketsPending = cursor.getInt( col );
}
switch ( summary.conType ) { switch ( summary.conType ) {
case COMMS_CONN_RELAY: case COMMS_CONN_RELAY:
col = cursor.getColumnIndex( DBHelper.ROOMNAME ); col = cursor.getColumnIndex( DBHelper.ROOMNAME );
@ -295,6 +301,7 @@ public class DBUtils {
if ( null != summary.conType ) { if ( null != summary.conType ) {
values.put( DBHelper.CONTYPE, summary.conType.ordinal() ); values.put( DBHelper.CONTYPE, summary.conType.ordinal() );
values.put( DBHelper.SEED, summary.seed ); values.put( DBHelper.SEED, summary.seed );
values.put( DBHelper.NPACKETSPENDING, summary.nPacketsPending );
switch( summary.conType ) { switch( summary.conType ) {
case COMMS_CONN_RELAY: case COMMS_CONN_RELAY:
values.put( DBHelper.ROOMNAME, summary.roomName ); values.put( DBHelper.ROOMNAME, summary.roomName );
@ -493,6 +500,30 @@ public class DBUtils {
return result; return result;
} }
public static HashMap<Long,CommsConnType>
getGamesWithSendsPending( Context context )
{
HashMap<Long, CommsConnType> result = new HashMap<Long,CommsConnType>();
String[] columns = { ROW_ID, DBHelper.CONTYPE };
String selection = String.format( "%s > 0", DBHelper.NPACKETSPENDING );
initDB( context );
synchronized( s_dbHelper ) {
SQLiteDatabase db = s_dbHelper.getReadableDatabase();
Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns,
selection, null, null, null, null );
int indx1 = cursor.getColumnIndex( ROW_ID );
int indx2 = cursor.getColumnIndex( DBHelper.CONTYPE );
for ( int ii = 0; cursor.moveToNext(); ++ii ) {
long rowid = cursor.getLong( indx1 );
CommsConnType typ = CommsConnType.values()[cursor.getInt(indx2)];
result.put( rowid, typ );
}
cursor.close();
db.close();
}
return result;
}
public static long[] getRowIDsFor( Context context, String relayID ) public static long[] getRowIDsFor( Context context, String relayID )
{ {
long[] result = null; long[] result = null;
@ -610,19 +641,20 @@ public class DBUtils {
NetLaunchInfo nli ) NetLaunchInfo nli )
{ {
Date result = null; Date result = null;
String[] columns = { DBHelper.CREATE_TIME }; String[] selectionArgs = new String[] {
String selection =
String.format( "%s='%s' AND %s='%s' AND %s=%d AND %s=%d",
DBHelper.ROOMNAME, nli.room, DBHelper.ROOMNAME, nli.room,
DBHelper.INVITEID, nli.inviteID, DBHelper.INVITEID, nli.inviteID,
DBHelper.DICTLANG, nli.lang, DBHelper.DICTLANG, String.format( "%d", nli.lang ),
DBHelper.NUM_PLAYERS, nli.nPlayersT ); DBHelper.NUM_PLAYERS, String.format( "%d", nli.nPlayersT )
};
initDB( context ); initDB( context );
synchronized( s_dbHelper ) { synchronized( s_dbHelper ) {
SQLiteDatabase db = s_dbHelper.getReadableDatabase(); SQLiteDatabase db = s_dbHelper.getReadableDatabase();
Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns, Cursor cursor = db.rawQuery( "SELECT " + DBHelper.CREATE_TIME +
selection, null, null, null, " FROM " + DBHelper.TABLE_NAME_SUM +
DBHelper.CREATE_TIME + " DESC" ); // order by " WHERE ?=? AND ?=? AND ?=? AND ?=?",
selectionArgs );
if ( cursor.moveToNext() ) { if ( cursor.moveToNext() ) {
int indx = cursor.getColumnIndex( DBHelper.CREATE_TIME ); int indx = cursor.getColumnIndex( DBHelper.CREATE_TIME );
result = new Date( cursor.getLong( indx ) ); result = new Date( cursor.getLong( indx ) );
@ -932,14 +964,16 @@ public class DBUtils {
// Groups stuff // Groups stuff
public static class GameGroupInfo { public static class GameGroupInfo {
public String m_name; public String m_name;
public int m_count;
public boolean m_expanded; public boolean m_expanded;
public long m_lastMoveTime; public long m_lastMoveTime;
public boolean m_hasTurn; public boolean m_hasTurn;
public boolean m_turnLocal; public boolean m_turnLocal;
public GameGroupInfo( String name, boolean expanded ) { public GameGroupInfo( String name, int count, boolean expanded ) {
m_name = name; m_expanded = expanded; m_name = name; m_expanded = expanded;
m_lastMoveTime = 0; m_lastMoveTime = 0;
m_count = count;
} }
} }
@ -978,44 +1012,58 @@ public class DBUtils {
return thumb; return thumb;
} }
// Return map of string (group name) to info about all games in private static HashMap<Long, Integer> getGameCounts( SQLiteDatabase db )
// that group.
public static HashMap<Long,GameGroupInfo> getGroups( Context context )
{ {
return getGroups( context, 0 ); HashMap<Long, Integer> result = new HashMap<Long, Integer>();
String query = "SELECT %s, count(%s) as cnt FROM %s GROUP BY %s";
query = String.format( query, DBHelper.GROUPID, DBHelper.GROUPID,
DBHelper.TABLE_NAME_SUM, DBHelper.GROUPID );
Cursor cursor = db.rawQuery( query, null );
int rowIndex = cursor.getColumnIndex( DBHelper.GROUPID );
int cntIndex = cursor.getColumnIndex( "cnt" );
while ( cursor.moveToNext() ) {
long row = cursor.getLong(rowIndex);
int count = cursor.getInt(cntIndex);
result.put( row, count );
}
cursor.close();
return result;
} }
private static HashMap<Long,GameGroupInfo> getGroups( Context context, // Map of groups rowid (= summaries.groupid) to group info record
int nRows ) protected static HashMap<Long,GameGroupInfo> getGroups( Context context )
{ {
if ( null == s_groupsCache ) { if ( null == s_groupsCache ) {
HashMap<Long,GameGroupInfo> result = HashMap<Long,GameGroupInfo> result =
new HashMap<Long,GameGroupInfo>(); new HashMap<Long,GameGroupInfo>();
String[] columns = { ROW_ID, DBHelper.GROUPNAME,
DBHelper.EXPANDED }; // Select all groups. For each group get the number of games in
String limit = 0 == nRows ? null : String.format( "%d", nRows ); // that group. There should be a way to do that with one query
// but I can't figure it out.
String query = "SELECT rowid, groupname as groups_groupname, "
+ " groups.expanded as groups_expanded FROM groups";
DbgUtils.logf( "query: %s", query );
initDB( context ); initDB( context );
synchronized( s_dbHelper ) { synchronized( s_dbHelper ) {
SQLiteDatabase db = s_dbHelper.getReadableDatabase(); SQLiteDatabase db = s_dbHelper.getReadableDatabase();
Cursor cursor = db.query( DBHelper.TABLE_NAME_GROUPS, columns,
null, // selection HashMap<Long, Integer> map = getGameCounts( db );
null, // args
null, // groupBy Cursor cursor = db.rawQuery( query, null );
null, // having int idIndex = cursor.getColumnIndex( "rowid" );
null, //orderby int nameIndex = cursor.getColumnIndex( "groups_groupname" );
limit int expandedIndex = cursor.getColumnIndex( "groups_expanded" );
);
int idIndex = cursor.getColumnIndex( ROW_ID );
int nameIndex = cursor.getColumnIndex( DBHelper.GROUPNAME );
int expandedIndex = cursor.getColumnIndex( DBHelper.EXPANDED );
while ( cursor.moveToNext() ) { while ( cursor.moveToNext() ) {
String name = cursor.getString( nameIndex );
long id = cursor.getLong( idIndex ); long id = cursor.getLong( idIndex );
String name = cursor.getString( nameIndex );
Assert.assertNotNull( name ); Assert.assertNotNull( name );
boolean expanded = 0 != cursor.getInt( expandedIndex ); boolean expanded = 0 != cursor.getInt( expandedIndex );
result.put( id, new GameGroupInfo( name, expanded ) ); int count = map.containsKey( id ) ? map.get( id ) : 0;
result.put( id, new GameGroupInfo( name, count, expanded ) );
} }
cursor.close(); cursor.close();
@ -1104,6 +1152,28 @@ public class DBUtils {
} }
} }
public static int countGames( Context context )
{
int result = 0;
String[] columns = { ROW_ID };
initDB( context );
synchronized( s_dbHelper ) {
SQLiteDatabase db = s_dbHelper.getReadableDatabase();
Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns,
null, // selection
null, // args
null, // groupBy
null, // having
null
);
result = cursor.getCount();
cursor.close();
db.close();
}
DbgUtils.logf( "DBUtils.countGames()=>%d", result );
return result;
}
public static long[] getGroupGames( Context context, long groupID ) public static long[] getGroupGames( Context context, long groupID )
{ {
long[] result = null; long[] result = null;
@ -1170,7 +1240,7 @@ public class DBUtils {
public static long getAnyGroup( Context context ) public static long getAnyGroup( Context context )
{ {
long result = GROUPID_UNSPEC; long result = GROUPID_UNSPEC;
HashMap<Long,GameGroupInfo> groups = getGroups( context, 1 ); HashMap<Long,GameGroupInfo> groups = getGroups( context );
Iterator<Long> iter = groups.keySet().iterator(); Iterator<Long> iter = groups.keySet().iterator();
if ( iter.hasNext() ) { if ( iter.hasNext() ) {
result = iter.next(); result = iter.next();
@ -1564,6 +1634,96 @@ public class DBUtils {
return colNames; return colNames;
} }
public static void addToStudyList( Context context, String word,
int lang )
{
ContentValues values = new ContentValues();
values.put( DBHelper.WORD, word );
values.put( DBHelper.LANGUAGE, lang );
initDB( context );
synchronized( s_dbHelper ) {
SQLiteDatabase db = s_dbHelper.getWritableDatabase();
db.insert( DBHelper.TABLE_NAME_STUDYLIST, null, values );
db.close();
}
}
public static int[] studyListLangs( Context context )
{
int[] result = null;
String groupBy = DBHelper.LANGUAGE;
String selection = null;//DBHelper.LANGUAGE;
String[] columns = { DBHelper.LANGUAGE };
initDB( context );
synchronized( s_dbHelper ) {
SQLiteDatabase db = s_dbHelper.getReadableDatabase();
Cursor cursor = db.query( DBHelper.TABLE_NAME_STUDYLIST, columns,
null, null, groupBy, null, null );
int count = cursor.getCount();
result = new int[count];
if ( 0 < count ) {
int index = 0;
int colIndex = cursor.getColumnIndex( DBHelper.LANGUAGE );
while ( cursor.moveToNext() ) {
result[index++] = cursor.getInt(colIndex);
}
}
cursor.close();
db.close();
}
return result;
}
public static String[] studyListWords( Context context, int lang )
{
String[] result = null;
String selection = String.format( "%s = %d", DBHelper.LANGUAGE, lang );
String[] columns = { DBHelper.WORD };
String orderBy = DBHelper.WORD;
initDB( context );
synchronized( s_dbHelper ) {
SQLiteDatabase db = s_dbHelper.getReadableDatabase();
Cursor cursor = db.query( DBHelper.TABLE_NAME_STUDYLIST, columns,
selection, null, null, null, orderBy );
int count = cursor.getCount();
result = new String[count];
if ( 0 < count ) {
int index = 0;
int colIndex = cursor.getColumnIndex( DBHelper.WORD );
while ( cursor.moveToNext() ) {
result[index++] = cursor.getString(colIndex);
}
}
cursor.close();
db.close();
}
return result;
}
public static void studyListClear( Context context, int lang, String[] words )
{
String selection = String.format( "%s = %d", DBHelper.LANGUAGE, lang );
if ( null != words ) {
selection += String.format( " AND %s in ('%s')", DBHelper.WORD,
TextUtils.join("','", words) );
}
initDB( context );
synchronized( s_dbHelper ) {
SQLiteDatabase db = s_dbHelper.getWritableDatabase();
db.delete( DBHelper.TABLE_NAME_STUDYLIST, selection, null );
db.close();
}
}
public static void studyListClear( Context context, int lang )
{
studyListClear( context, lang, null );
}
private static void copyGameDB( Context context, boolean toSDCard ) private static void copyGameDB( Context context, boolean toSDCard )
{ {
String name = DBHelper.getDBName(); String name = DBHelper.getDBName();

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/* /*
* Copyright 2009-2011 by Eric House (xwords@eehouse.org). All * Copyright 2009-2011 by Eric House (xwords@eehouse.org). All
* rights reserved. * rights reserved.

View file

@ -0,0 +1,172 @@
/* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/*
* Copyright 2014 by Eric House (xwords@eehouse.org). All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.eehouse.android.xw4;
import android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;
import org.eehouse.android.xw4.DlgDelegate.Action;
import junit.framework.Assert;
public class DelegateBase implements DlgDelegate.DlgClickNotify,
DlgDelegate.HasDlgDelegate,
MultiService.MultiEventListener {
private DlgDelegate m_delegate;
public DelegateBase( Activity activity, Bundle bundle )
{
m_delegate = new DlgDelegate( activity, this, bundle );
}
protected void showDialog( DlgID dlgID )
{
m_delegate.showDialog( dlgID );
}
protected Dialog createDialog( int id )
{
return m_delegate.createDialog( id );
}
protected void showNotAgainDlgThen( int msgID, int prefsKey,
Action action, Object... params )
{
m_delegate.showNotAgainDlgThen( msgID, prefsKey, action, params );
}
public void showNotAgainDlgThen( int msgID, int prefsKey, Action action )
{
m_delegate.showNotAgainDlgThen( msgID, prefsKey, action );
}
protected void showNotAgainDlgThen( String msg, int prefsKey,
Action action )
{
m_delegate.showNotAgainDlgThen( msg, prefsKey, action, null );
}
protected void showNotAgainDlg( int msgID, int prefsKey )
{
m_delegate.showNotAgainDlgThen( msgID, prefsKey );
}
protected void showNotAgainDlgThen( int msgID, int prefsKey )
{
m_delegate.showNotAgainDlgThen( msgID, prefsKey );
}
// It sucks that these must be duplicated here and XWActivity
protected void showAboutDialog()
{
m_delegate.showAboutDialog();
}
public void showOKOnlyDialog( int msgID )
{
m_delegate.showOKOnlyDialog( msgID );
}
public void showOKOnlyDialog( String msg )
{
m_delegate.showOKOnlyDialog( msg );
}
protected void showConfirmThen( String msg, Action action, Object... params )
{
m_delegate.showConfirmThen( msg, action, params );
}
protected void showConfirmThen( String msg, int posButton, Action action,
Object... params )
{
m_delegate.showConfirmThen( msg, posButton, action, params );
}
protected void showConfirmThen( int msg, int posButton, Action action,
Object... params )
{
m_delegate.showConfirmThen( msg, posButton, action, params );
}
protected void showConfirmThen( int msgID, Action action )
{
m_delegate.showConfirmThen( msgID, action );
}
protected boolean post( Runnable runnable )
{
return m_delegate.post( runnable );
}
protected void doSyncMenuitem()
{
m_delegate.doSyncMenuitem();
}
protected void launchLookup( String[] words, int lang, boolean noStudy )
{
m_delegate.launchLookup( words, lang, noStudy );
}
protected void launchLookup( String[] words, int lang )
{
m_delegate.launchLookup( words, lang, false );
}
protected void showInviteChoicesThen( Action action )
{
m_delegate.showInviteChoicesThen( action );
}
protected void startProgress( int id )
{
m_delegate.startProgress( id );
}
protected void stopProgress()
{
m_delegate.stopProgress();
}
protected void showDictGoneFinish()
{
m_delegate.showDictGoneFinish();
}
//////////////////////////////////////////////////
// MultiService.MultiEventListener interface
//////////////////////////////////////////////////
public void eventOccurred( MultiService.MultiEvent event, final Object ... args )
{
Assert.fail();
}
//////////////////////////////////////////////////////////////////////
// DlgDelegate.DlgClickNotify interface
//////////////////////////////////////////////////////////////////////
public void dlgButtonClicked( Action action, int button, Object[] params )
{
Assert.fail();
}
}

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/* /*
* Copyright 2009 - 2011 by Eric House (xwords@eehouse.org). All * Copyright 2009 - 2011 by Eric House (xwords@eehouse.org). All
* rights reserved. * rights reserved.
@ -42,6 +42,7 @@ import java.util.Arrays;
import junit.framework.Assert; import junit.framework.Assert;
import org.eehouse.android.xw4.DlgDelegate.Action;
import org.eehouse.android.xw4.jni.JNIUtilsImpl; import org.eehouse.android.xw4.jni.JNIUtilsImpl;
import org.eehouse.android.xw4.jni.XwJNI; import org.eehouse.android.xw4.jni.XwJNI;
@ -52,7 +53,6 @@ public class DictBrowseActivity extends XWListActivity
private static final String DICT_LOC = "DICT_LOC"; private static final String DICT_LOC = "DICT_LOC";
private static final int MIN_LEN = 2; private static final int MIN_LEN = 2;
private static final int FINISH_ACTION = 1;
private int m_dictClosure = 0; private int m_dictClosure = 0;
private int m_lang; private int m_lang;
@ -194,7 +194,7 @@ public class DictBrowseActivity extends XWListActivity
// search/minmax stuff. // search/minmax stuff.
String msg = Utils.format( this, R.string.alert_empty_dictf, String msg = Utils.format( this, R.string.alert_empty_dictf,
name ); name );
showOKOnlyDialogThen( msg, FINISH_ACTION ); showOKOnlyDialogThen( msg, Action.FINISH_ACTION );
} else { } else {
figureMinMax( m_browseState.m_counts ); figureMinMax( m_browseState.m_counts );
if ( newState ) { if ( newState ) {
@ -288,6 +288,8 @@ public class DictBrowseActivity extends XWListActivity
int position, long id ) int position, long id )
{ {
TextView text = (TextView)view; TextView text = (TextView)view;
// null text seems to have generated at least one google play report
if ( null != text ) {
int newval = Integer.parseInt( text.getText().toString() ); int newval = Integer.parseInt( text.getText().toString() );
if ( parent == m_minSpinner ) { if ( parent == m_minSpinner ) {
setMinMax( newval, m_browseState.m_maxShown ); setMinMax( newval, m_browseState.m_maxShown );
@ -295,6 +297,7 @@ public class DictBrowseActivity extends XWListActivity
setMinMax( m_browseState.m_minShown, newval ); setMinMax( m_browseState.m_minShown, newval );
} }
} }
}
public void onNothingSelected( AdapterView<?> parent ) public void onNothingSelected( AdapterView<?> parent )
{ {
@ -304,9 +307,9 @@ public class DictBrowseActivity extends XWListActivity
// DlgDelegate.DlgClickNotify interface // DlgDelegate.DlgClickNotify interface
////////////////////////////////////////////////// //////////////////////////////////////////////////
@Override @Override
public void dlgButtonClicked( int id, int which, Object[] params ) public void dlgButtonClicked( Action action, int which, Object[] params )
{ {
Assert.assertTrue( FINISH_ACTION == id ); Assert.assertTrue( Action.FINISH_ACTION == action );
finish(); finish();
} }

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/* /*
* Copyright 2009-2012 by Eric House (xwords@eehouse.org). All rights * Copyright 2009-2012 by Eric House (xwords@eehouse.org). All rights
* reserved. * reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/* /*
* Copyright 2010 by Eric House (xwords@eehouse.org). All rights * Copyright 2010 by Eric House (xwords@eehouse.org). All rights
* reserved. * reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/* /*
* Copyright 2010 by Eric House (xwords@eehouse.org). All * Copyright 2010 by Eric House (xwords@eehouse.org). All
* rights reserved. * rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/* /*
* Copyright 2009-2011 by Eric House (xwords@eehouse.org). All rights * Copyright 2009-2011 by Eric House (xwords@eehouse.org). All rights
* reserved. * reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/* /*
* Copyright 2009 - 2012 by Eric House (xwords@eehouse.org). All * Copyright 2009 - 2012 by Eric House (xwords@eehouse.org). All
* rights reserved. * rights reserved.
@ -20,10 +20,10 @@
package org.eehouse.android.xw4; package org.eehouse.android.xw4;
import android.text.TextUtils;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
import android.app.ExpandableListActivity;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface.OnClickListener; import android.content.DialogInterface.OnClickListener;
import android.content.DialogInterface; import android.content.DialogInterface;
@ -34,16 +34,17 @@ import android.database.DataSetObserver;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.text.TextUtils;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.Button; import android.widget.Button;
import android.widget.ExpandableListAdapter; import android.widget.ExpandableListAdapter;
import android.widget.ExpandableListView; import android.widget.ExpandableListView;
import android.widget.AdapterView;
import android.widget.PopupMenu; import android.widget.PopupMenu;
import android.widget.TextView; import android.widget.TextView;
@ -54,315 +55,32 @@ import java.util.Iterator;
import junit.framework.Assert; import junit.framework.Assert;
import org.eehouse.android.xw4.DlgDelegate.Action;
import org.eehouse.android.xw4.DictUtils.DictAndLoc; import org.eehouse.android.xw4.DictUtils.DictAndLoc;
import org.eehouse.android.xw4.jni.XwJNI; import org.eehouse.android.xw4.jni.XwJNI;
import org.eehouse.android.xw4.jni.JNIUtilsImpl; import org.eehouse.android.xw4.jni.JNIUtilsImpl;
import org.eehouse.android.xw4.jni.GameSummary; import org.eehouse.android.xw4.jni.GameSummary;
import org.eehouse.android.xw4.DictUtils.DictLoc; import org.eehouse.android.xw4.DictUtils.DictLoc;
public class DictsActivity extends XWExpandableListActivity public class DictsActivity extends ExpandableListActivity {
implements View.OnClickListener, AdapterView.OnItemLongClickListener,
SelectableItem, MountEventReceiver.SDCardNotifiee,
DlgDelegate.DlgClickNotify,
DictImportActivity.DownloadFinishedListener {
private static interface SafePopup { private static interface SafePopup {
public void doPopup( Context context, View button, String curDict ); public void doPopup( Context context, View button, String curDict );
} }
private static SafePopup s_safePopup = null; private static SafePopup s_safePopup = null;
private static final String DICT_DOLAUNCH = "do_launch";
private static final String DICT_LANG_EXTRA = "use_lang";
private static final String DICT_NAME_EXTRA = "use_dict";
private HashSet<String> m_closedLangs;
// For new callback alternative
private static final int DELETE_DICT_ACTION = 1;
private static final int DOWNLOAD_DICT_ACTION = 2;
private static final int MOVE_DICT = DlgDelegate.DIALOG_LAST + 1;
private static final int SET_DEFAULT = DlgDelegate.DIALOG_LAST + 2;
private static final int DICT_OR_DECLINE = DlgDelegate.DIALOG_LAST + 3;
// I can't provide a subclass of MenuItem to hold DictAndLoc, so // I can't provide a subclass of MenuItem to hold DictAndLoc, so
// settle for a hash on the side. // settle for a hash on the side.
private static HashMap<MenuItem, DictAndLoc> s_itemData; private static HashMap<MenuItem, DictAndLoc> s_itemData;
private String[] m_langs; private DictsDelegate m_dlgt;
private String m_download;
private ExpandableListView m_expView;
private String[] m_locNames;
private DictListAdapter m_adapter;
private HashSet<XWListItem> m_selDicts;
private CharSequence m_origTitle;
private boolean m_launchedForMissing = false;
private LayoutInflater m_factory;
private class DictListAdapter implements ExpandableListAdapter {
private Context m_context;
private XWListItem[][] m_cache;
public DictListAdapter( Context context ) {
m_context = context;
}
public boolean areAllItemsEnabled() { return false; }
public Object getChild( int groupPosition, int childPosition )
{
return null;
}
public long getChildId( int groupPosition, int childPosition )
{
return childPosition;
}
public View getChildView( int groupPosition, int childPosition,
boolean isLastChild, View convertView,
ViewGroup parent)
{
return getChildView( groupPosition, childPosition );
}
private View getChildView( int groupPosition, int childPosition )
{
XWListItem view = null;
if ( null != m_cache && null != m_cache[groupPosition] ) {
view = m_cache[groupPosition][childPosition];
}
if ( null == view ) {
view = (XWListItem)
m_factory.inflate( R.layout.list_item, null );
view.setSelCB( DictsActivity.this );
int lang = (int)getGroupId( groupPosition );
DictAndLoc[] dals = DictLangCache.getDALsHaveLang( m_context,
lang );
if ( null != dals && childPosition < dals.length ) {
DictAndLoc dal;
dal = dals[childPosition];
view.setText( dal.name );
DictLoc loc = dal.loc;
view.setComment( m_locNames[loc.ordinal()] );
view.cache( loc );
} else {
view.setText( m_download );
}
addToCache( groupPosition, childPosition, view );
view.setOnClickListener( DictsActivity.this );
}
return view;
}
public int getChildrenCount( int groupPosition )
{
int lang = (int)getGroupId( groupPosition );
DictAndLoc[] dals = DictLangCache.getDALsHaveLang( m_context, lang );
int result = 0; // 1; // 1 for the download option
if ( null != dals ) {
result += dals.length;
}
return result;
}
public long getCombinedChildId( long groupId, long childId )
{
return groupId << 16 | childId;
}
public long getCombinedGroupId( long groupId )
{
return groupId;
}
public Object getGroup( int groupPosition )
{
return null;
}
public int getGroupCount()
{
return m_langs.length;
}
public long getGroupId( int groupPosition )
{
int lang = DictLangCache.getLangLangCode( m_context,
m_langs[groupPosition] );
return lang;
}
public View getGroupView( int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent )
{
View row =
Utils.inflate(DictsActivity.this,
android.R.layout.simple_expandable_list_item_1 );
TextView view = (TextView)row.findViewById( android.R.id.text1 );
view.setText( m_langs[groupPosition] );
return view;
}
public boolean hasStableIds() { return false; }
public boolean isChildSelectable( int groupPosition,
int childPosition ) { return true; }
public boolean isEmpty() { return false; }
public void onGroupCollapsed(int groupPosition)
{
m_closedLangs.add( m_langs[groupPosition] );
saveClosed();
}
public void onGroupExpanded(int groupPosition){
m_closedLangs.remove( m_langs[groupPosition] );
saveClosed();
}
public void registerDataSetObserver( DataSetObserver obs ){}
public void unregisterDataSetObserver( DataSetObserver obs ){}
protected XWListItem getSelChildView()
{
Assert.assertTrue( 1 == m_selDicts.size() );
return m_selDicts.iterator().next();
}
private void addToCache( int group, int child, XWListItem view )
{
if ( null == m_cache ) {
m_cache = new XWListItem[getGroupCount()][];
}
if ( null == m_cache[group] ) {
m_cache[group] = new XWListItem[getChildrenCount(group)];
}
Assert.assertTrue( null == m_cache[group][child] );
m_cache[group][child] = view;
}
}
@Override @Override
protected Dialog onCreateDialog( int id ) protected Dialog onCreateDialog( int id )
{ {
OnClickListener lstnr, lstnr2; Dialog dialog = super.onCreateDialog( id );
Dialog dialog; if ( null == dialog ) {
String format; dialog = m_dlgt.createDialog( id );
String message;
boolean doRemove = true;
switch( id ) {
case MOVE_DICT:
final XWListItem[] selItems = getSelItems();
final int[] moveTo = { -1 };
message = Utils.format( this, R.string.move_dictf,
getJoinedNames( selItems ) );
OnClickListener newSelLstnr =
new OnClickListener() {
public void onClick( DialogInterface dlgi, int item ) {
moveTo[0] = item;
AlertDialog dlg = (AlertDialog)dlgi;
Button btn =
dlg.getButton( AlertDialog.BUTTON_POSITIVE );
btn.setEnabled( true );
} }
};
lstnr = new OnClickListener() {
public void onClick( DialogInterface dlg, int item ) {
DictLoc toLoc = itemToRealLoc( moveTo[0] );
for ( XWListItem selItem : selItems ) {
DictLoc fromLoc = (DictLoc)selItem.getCached();
String name = selItem.getText();
if ( fromLoc == toLoc ) {
DbgUtils.logf( "not moving %s: same loc", name );
} else if ( DictUtils.moveDict( DictsActivity.this,
name, fromLoc,
toLoc ) ) {
selItem.setComment( m_locNames[toLoc.ordinal()] );
selItem.cache( toLoc );
selItem.invalidate();
DBUtils.dictsMoveInfo( DictsActivity.this,
name, fromLoc, toLoc );
} else {
DbgUtils.logf( "moveDict(%s) failed", name );
}
}
}
};
dialog = new AlertDialog.Builder( this )
.setTitle( message )
.setSingleChoiceItems( makeDictDirItems(), moveTo[0],
newSelLstnr )
.setPositiveButton( R.string.button_move, lstnr )
.setNegativeButton( R.string.button_cancel, null )
.create();
break;
case SET_DEFAULT:
final XWListItem row = m_selDicts.iterator().next();
lstnr = new OnClickListener() {
public void onClick( DialogInterface dlg, int item ) {
if ( DialogInterface.BUTTON_NEGATIVE == item
|| DialogInterface.BUTTON_POSITIVE == item ) {
setDefault( row, R.string.key_default_dict );
}
if ( DialogInterface.BUTTON_NEGATIVE == item
|| DialogInterface.BUTTON_NEUTRAL == item ) {
setDefault( row, R.string.key_default_robodict );
}
}
};
String name = row.getText();
String lang = DictLangCache.getLangName( this, name);
message = getString( R.string.set_default_messagef, name, lang );
dialog = new AlertDialog.Builder( this )
.setTitle( R.string.query_title )
.setMessage( message )
.setPositiveButton( R.string.button_default_human, lstnr )
.setNeutralButton( R.string.button_default_robot, lstnr )
.setNegativeButton( R.string.button_default_both, lstnr )
.create();
break;
case DICT_OR_DECLINE:
lstnr = new OnClickListener() {
public void onClick( DialogInterface dlg, int item ) {
Intent intent = getIntent();
int lang = intent.getIntExtra( MultiService.LANG, -1 );
String name = intent.getStringExtra( MultiService.DICT );
m_launchedForMissing = true;
DictImportActivity
.downloadDictInBack( DictsActivity.this, lang,
name, DictsActivity.this );
}
};
lstnr2 = new OnClickListener() {
public void onClick( DialogInterface dlg, int item ) {
finish();
}
};
dialog = MultiService.missingDictDialog( this, getIntent(),
lstnr, lstnr2 );
break;
default:
dialog = super.onCreateDialog( id );
doRemove = false;
break;
}
if ( doRemove && null != dialog ) {
Utils.setRemoveOnDismiss( this, dialog, id );
}
return dialog; return dialog;
} // onCreateDialog } // onCreateDialog
@ -370,402 +88,53 @@ public class DictsActivity extends XWExpandableListActivity
protected void onPrepareDialog( int id, Dialog dialog ) protected void onPrepareDialog( int id, Dialog dialog )
{ {
super.onPrepareDialog( id, dialog ); super.onPrepareDialog( id, dialog );
m_dlgt.prepareDialog( id, dialog );
if ( MOVE_DICT == id ) {
// The move button should always start out disabled
// because the selected location should be where it
// currently is.
((AlertDialog)dialog).getButton( AlertDialog.BUTTON_POSITIVE )
.setEnabled( false );
}
} }
@Override @Override
protected void onCreate( Bundle savedInstanceState ) protected void onCreate( Bundle savedInstanceState )
{ {
super.onCreate( savedInstanceState ); super.onCreate( savedInstanceState );
m_dlgt = new DictsDelegate( this, savedInstanceState );
m_closedLangs = new HashSet<String>();
String[] closed = XWPrefs.getClosedLangs( this );
if ( null != closed ) {
for ( String str : closed ) {
m_closedLangs.add( str );
}
}
Resources res = getResources();
m_locNames = res.getStringArray( R.array.loc_names );
m_factory = LayoutInflater.from( this );
m_download = getString( R.string.download_dicts );
setContentView( R.layout.dict_browse );
m_expView = getExpandableListView();
m_expView.setOnItemLongClickListener( this );
Button download = (Button)findViewById( R.id.download );
if ( ABUtils.haveActionBar() ) {
download.setVisibility( View.GONE );
} else {
download.setOnClickListener( this );
}
mkListAdapter();
m_selDicts = new HashSet<XWListItem>();
Intent intent = getIntent();
if ( null != intent ) {
if ( MultiService.isMissingDictIntent( intent ) ) {
showDialog( DICT_OR_DECLINE );
} else {
boolean downloadNow = intent.getBooleanExtra( DICT_DOLAUNCH, false );
if ( downloadNow ) {
int lang = intent.getIntExtra( DICT_LANG_EXTRA, 0 );
String name = intent.getStringExtra( DICT_NAME_EXTRA );
startDownload( lang, name );
}
downloadNewDict( intent );
}
}
m_origTitle = getTitle();
} // onCreate } // onCreate
@Override @Override
protected void onResume() protected void onResume()
{ {
super.onResume(); super.onResume();
MountEventReceiver.register( this ); m_dlgt.onResume();
mkListAdapter();
expandGroups();
} }
@Override @Override
protected void onStop() { protected void onStop() {
MountEventReceiver.unregister( this ); m_dlgt.onStop();
super.onStop(); super.onStop();
} }
public void onClick( View view )
{
if ( view instanceof Button ) {
startDownload( 0, null );
} else {
XWListItem item = (XWListItem)view;
DictBrowseActivity.launch( this, item.getText(),
(DictLoc)item.getCached() );
}
}
@Override @Override
public void onBackPressed() { public void onBackPressed() {
if ( 0 == m_selDicts.size() ) { if ( !m_dlgt.onBackPressed() ) {
super.onBackPressed(); super.onBackPressed();
} else {
clearSelections();
} }
} }
@Override @Override
public boolean onCreateOptionsMenu( Menu menu ) public boolean onCreateOptionsMenu( Menu menu )
{ {
MenuInflater inflater = getMenuInflater(); return m_dlgt.onCreateOptionsMenu( menu );
inflater.inflate( R.menu.dicts_menu, menu );
return true;
} }
@Override @Override
public boolean onPrepareOptionsMenu( Menu menu ) public boolean onPrepareOptionsMenu( Menu menu )
{ {
int nSel = m_selDicts.size(); return m_dlgt.onPrepareOptionsMenu( menu )
Utils.setItemVisible( menu, R.id.dicts_download, || super.onPrepareOptionsMenu( menu );
0 == nSel && ABUtils.haveActionBar() );
Utils.setItemVisible( menu, R.id.dicts_select, 1 == nSel );
boolean allVolatile = selItemsVolatile();
Utils.setItemVisible( menu, R.id.dicts_move,
allVolatile && DictUtils.haveWriteableSD() );
Utils.setItemVisible( menu, R.id.dicts_delete, allVolatile );
return super.onPrepareOptionsMenu( menu );
} }
public boolean onOptionsItemSelected( MenuItem item ) public boolean onOptionsItemSelected( MenuItem item )
{ {
boolean handled = true; return m_dlgt.onOptionsItemSelected( item )
|| super.onOptionsItemSelected( item );
switch ( item.getItemId() ) {
case R.id.dicts_download:
startDownload( 0, null );
break;
case R.id.dicts_delete:
deleteSelected();
break;
case R.id.dicts_move:
askMoveSelDicts();
break;
case R.id.dicts_select:
showDialog( SET_DEFAULT );
break;
default:
handled = false;
}
return handled || super.onOptionsItemSelected( item );
}
private void downloadNewDict( Intent intent )
{
int loci = intent.getIntExtra( UpdateCheckReceiver.NEW_DICT_LOC, 0 );
if ( 0 < loci ) {
String url =
intent.getStringExtra( UpdateCheckReceiver.NEW_DICT_URL );
DictImportActivity.downloadDictInBack( this, url );
finish();
}
}
private void setDefault( XWListItem view, int keyId )
{
SharedPreferences sp
= PreferenceManager.getDefaultSharedPreferences( this );
SharedPreferences.Editor editor = sp.edit();
String key = getString( keyId );
String name = view.getText();
editor.putString( key, name );
editor.commit();
}
// Move dict. Put up dialog asking user to confirm move from XX
// to YY. So we need both XX and YY. There may be several
// options for YY?
private void askMoveSelDicts()
{
showDialog( MOVE_DICT );
}
// OnItemLongClickListener interface
public boolean onItemLongClick( AdapterView<?> parent, View view,
int position, long id ) {
boolean success = view instanceof SelectableItem.LongClickHandler;
if ( success ) {
((SelectableItem.LongClickHandler)view).longClicked();
}
return success;
}
private boolean selItemsVolatile()
{
boolean result = 0 < m_selDicts.size();
for ( Iterator<XWListItem> iter = m_selDicts.iterator();
result && iter.hasNext(); ) {
DictLoc loc = (DictLoc)iter.next().getCached();
if ( loc == DictLoc.BUILT_IN ) {
result = false;
}
}
return result;
}
private void deleteSelected()
{
XWListItem[] items = getSelItems();
String msg = getString( R.string.confirm_delete_dictf,
getJoinedNames( items ) );
// When and what to warn about. First off, if there's another
// identical dict, simply confirm. Or if nobody's using this
// dict *and* it's not the last of a language that somebody's
// using, simply confirm. If somebody is using it, then we
// want different warnings depending on whether it's the last
// available dict in its language.
for ( XWListItem item : items ) {
String dict = item.getText();
if ( 1 < DictLangCache.getDictCount( this, dict ) ) {
// there's another; do nothing
} else {
String newMsg = null;
int langcode = DictLangCache.getDictLangCode( this, dict );
String langName = DictLangCache.getLangName( this, langcode );
DictAndLoc[] langDals = DictLangCache.getDALsHaveLang( this,
langcode );
int nUsingLang = DBUtils.countGamesUsingLang( this, langcode );
if ( 1 == langDals.length ) { // last in this language?
if ( 0 < nUsingLang ) {
newMsg = getString( R.string.confirm_deleteonly_dictf,
dict, langName );
}
} else if ( 0 < DBUtils.countGamesUsingDict( this, dict ) ) {
newMsg = getString( R.string.confirm_deletemore_dictf,
langName );
}
if ( null != newMsg ) {
msg += "\n\n" + newMsg;
}
}
}
showConfirmThen( msg, R.string.button_delete, DELETE_DICT_ACTION,
(Object)items );
} // deleteSelected
// MountEventReceiver.SDCardNotifiee interface
public void cardMounted( boolean nowMounted )
{
DbgUtils.logf( "DictsActivity.cardMounted(%b)", nowMounted );
// post so other SDCardNotifiee implementations get a chance
// to process first: avoid race conditions
post( new Runnable() {
public void run() {
mkListAdapter();
expandGroups();
}
} );
}
// DlgDelegate.DlgClickNotify interface
public void dlgButtonClicked( int id, int which, Object[] params )
{
switch( id ) {
case DELETE_DICT_ACTION:
if ( DialogInterface.BUTTON_POSITIVE == which ) {
XWListItem[] items = (XWListItem[])params[0];
for ( XWListItem item : items ) {
String name = item.getText();
DictLoc loc = (DictLoc)item.getCached();
deleteDict( name, loc );
}
clearSelections();
}
break;
case DOWNLOAD_DICT_ACTION:
startDownload( (Intent)params[0] );
break;
default:
Assert.fail();
}
}
private DictLoc itemToRealLoc( int item )
{
item += DictLoc.INTERNAL.ordinal();
return DictLoc.values()[item];
}
private void deleteDict( String dict, DictLoc loc )
{
DictUtils.deleteDict( this, dict, loc );
DictLangCache.inval( this, dict, loc, false );
mkListAdapter();
expandGroups();
}
private void startDownload( int lang, String name )
{
Intent intent = mkDownloadIntent( this, lang, name );
showNotAgainDlgThen( R.string.not_again_firefox,
R.string.key_na_firefox,
DOWNLOAD_DICT_ACTION, intent );
}
private void startDownload( Intent downloadIntent )
{
try {
startActivity( downloadIntent );
} catch ( android.content.ActivityNotFoundException anfe ) {
Utils.showToast( this, R.string.no_download_warning );
}
}
private void mkListAdapter()
{
m_langs = DictLangCache.listLangs( this );
Arrays.sort( m_langs );
m_adapter = new DictListAdapter( this );
setListAdapter( m_adapter );
}
private void expandGroups()
{
for ( int ii = 0; ii < m_langs.length; ++ii ) {
boolean open = true;
String lang = m_langs[ii];
if ( ! m_closedLangs.contains( lang ) ) {
m_expView.expandGroup( ii );
}
}
}
private void saveClosed()
{
String[] asArray = m_closedLangs.toArray( new String[m_closedLangs.size()] );
XWPrefs.setClosedLangs( this, asArray );
}
private void clearSelections()
{
if ( 0 < m_selDicts.size() ) {
XWListItem[] items = getSelItems();
m_selDicts.clear();
for ( XWListItem item : items ) {
item.setSelected( false );
}
}
}
private String getJoinedNames( XWListItem[] items )
{
String[] names = new String[items.length];
int ii = 0;
for ( XWListItem item : items ) {
names[ii++] = item.getText();
}
return TextUtils.join( ", ", names );
}
private XWListItem[] getSelItems()
{
XWListItem[] items = new XWListItem[m_selDicts.size()];
int indx = 0;
for ( Iterator<XWListItem> iter = m_selDicts.iterator();
iter.hasNext(); ) {
items[indx++] = iter.next();
}
return items;
}
private void setTitleBar()
{
int nSels = m_selDicts.size();
if ( 0 < nSels ) {
setTitle( getString( R.string.sel_dictsf, nSels ) );
} else {
setTitle( m_origTitle );
}
}
private String[] makeDictDirItems()
{
boolean showDownload = DictUtils.haveDownloadDir( this );
int nItems = showDownload ? 3 : 2;
int nextI = 0;
String[] items = new String[nItems];
for ( int ii = 0; ii < 3; ++ii ) {
DictLoc loc = itemToRealLoc(ii);
if ( !showDownload && DictLoc.DOWNLOAD == loc ) {
continue;
}
items[nextI++] = m_locNames[loc.ordinal()];
}
return items;
} }
private static Intent mkDownloadIntent( Context context, String dict_url ) private static Intent mkDownloadIntent( Context context, String dict_url )
@ -787,13 +156,13 @@ public class DictsActivity extends XWExpandableListActivity
String name ) String name )
{ {
Intent intent = new Intent( activity, DictsActivity.class ); Intent intent = new Intent( activity, DictsActivity.class );
intent.putExtra( DICT_DOLAUNCH, true ); intent.putExtra( DictsDelegate.DICT_DOLAUNCH, true );
if ( lang > 0 ) { if ( lang > 0 ) {
intent.putExtra( DICT_LANG_EXTRA, lang ); intent.putExtra( DictsDelegate.DICT_LANG_EXTRA, lang );
} }
if ( null != name ) { if ( null != name ) {
Assert.assertTrue( lang != 0 ); Assert.assertTrue( lang != 0 );
intent.putExtra( DICT_NAME_EXTRA, name ); intent.putExtra( DictsDelegate.DICT_NAME_EXTRA, name );
} }
activity.startActivity( intent ); activity.startActivity( intent );
@ -809,53 +178,6 @@ public class DictsActivity extends XWExpandableListActivity
launchAndDownload( activity, 0, null ); launchAndDownload( activity, 0, null );
} }
// DictImportActivity.DownloadFinishedListener interface
public void downloadFinished( String name, final boolean success )
{
if ( m_launchedForMissing ) {
post( new Runnable() {
public void run() {
if ( success ) {
Intent intent = getIntent();
if ( MultiService.returnOnDownload( DictsActivity.this,
intent ) ) {
finish();
}
} else {
Utils.showToast( DictsActivity.this,
R.string.download_failed );
}
}
} );
}
}
// SelectableItem interface
public void itemClicked( SelectableItem.LongClickHandler clicked,
GameSummary summary )
{
DbgUtils.logf( "itemClicked not implemented" );
}
public void itemToggled( SelectableItem.LongClickHandler toggled,
boolean selected )
{
XWListItem dictView = (XWListItem)toggled;
if ( selected ) {
m_selDicts.add( dictView );
} else {
m_selDicts.remove( dictView );
}
ABUtils.invalidateOptionsMenuIf( this );
setTitleBar();
}
public boolean getSelected( SelectableItem.LongClickHandler obj )
{
XWListItem dictView = (XWListItem)obj;
return m_selDicts.contains( dictView );
}
private static class SafePopupImpl implements SafePopup { private static class SafePopupImpl implements SafePopup {
public void doPopup( final Context context, View button, public void doPopup( final Context context, View button,
String curDict ) { String curDict ) {

View file

@ -0,0 +1,842 @@
/* -*- compile-command: "find-and-ant.sh 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.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ExpandableListActivity;
import android.content.Context;
import android.content.DialogInterface.OnClickListener;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.database.DataSetObserver;
import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.PopupMenu;
import android.widget.TextView;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import junit.framework.Assert;
import org.eehouse.android.xw4.DlgDelegate.Action;
import org.eehouse.android.xw4.DictUtils.DictAndLoc;
import org.eehouse.android.xw4.jni.XwJNI;
import org.eehouse.android.xw4.jni.JNIUtilsImpl;
import org.eehouse.android.xw4.jni.GameSummary;
import org.eehouse.android.xw4.DictUtils.DictLoc;
public class DictsDelegate extends DelegateBase
implements View.OnClickListener, AdapterView.OnItemLongClickListener,
SelectableItem, MountEventReceiver.SDCardNotifiee,
DlgDelegate.DlgClickNotify,
DictImportActivity.DownloadFinishedListener {
protected static final String DICT_DOLAUNCH = "do_launch";
protected static final String DICT_LANG_EXTRA = "use_lang";
protected static final String DICT_NAME_EXTRA = "use_dict";
private ExpandableListActivity m_activity;
private HashSet<String> m_closedLangs;
private String[] m_langs;
private String m_downloadStr;
private ExpandableListView m_expView;
private String[] m_locNames;
private DictListAdapter m_adapter;
private HashSet<XWListItem> m_selDicts;
private CharSequence m_origTitle;
private boolean m_launchedForMissing = false;
private LayoutInflater m_factory;
private class DictListAdapter implements ExpandableListAdapter {
private Context m_context;
private XWListItem[][] m_cache;
public DictListAdapter( Context context ) {
m_context = context;
}
public boolean areAllItemsEnabled() { return false; }
public Object getChild( int groupPosition, int childPosition )
{
return null;
}
public long getChildId( int groupPosition, int childPosition )
{
return childPosition;
}
public View getChildView( int groupPosition, int childPosition,
boolean isLastChild, View convertView,
ViewGroup parent)
{
return getChildView( groupPosition, childPosition );
}
private View getChildView( int groupPosition, int childPosition )
{
XWListItem view = null;
if ( null != m_cache && null != m_cache[groupPosition] ) {
view = m_cache[groupPosition][childPosition];
}
if ( null == view ) {
view = XWListItem.inflate( m_activity, DictsDelegate.this );
int lang = (int)getGroupId( groupPosition );
DictAndLoc[] dals = DictLangCache.getDALsHaveLang( m_context,
lang );
if ( null != dals && childPosition < dals.length ) {
DictAndLoc dal;
dal = dals[childPosition];
view.setText( dal.name );
DictLoc loc = dal.loc;
view.setComment( m_locNames[loc.ordinal()] );
view.cache( loc );
} else {
view.setText( m_downloadStr );
}
addToCache( groupPosition, childPosition, view );
view.setOnClickListener( DictsDelegate.this );
}
return view;
}
public int getChildrenCount( int groupPosition )
{
int lang = (int)getGroupId( groupPosition );
DictAndLoc[] dals = DictLangCache.getDALsHaveLang( m_context, lang );
int result = 0; // 1; // 1 for the download option
if ( null != dals ) {
result += dals.length;
}
return result;
}
public long getCombinedChildId( long groupId, long childId )
{
return groupId << 16 | childId;
}
public long getCombinedGroupId( long groupId )
{
return groupId;
}
public Object getGroup( int groupPosition )
{
return null;
}
public int getGroupCount()
{
return m_langs.length;
}
public long getGroupId( int groupPosition )
{
int lang = DictLangCache.getLangLangCode( m_context,
m_langs[groupPosition] );
return lang;
}
public View getGroupView( int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent )
{
View row =
Utils.inflate( m_activity,
android.R.layout.simple_expandable_list_item_1 );
TextView view = (TextView)row.findViewById( android.R.id.text1 );
view.setText( m_langs[groupPosition] );
return view;
}
public boolean hasStableIds() { return false; }
public boolean isChildSelectable( int groupPosition,
int childPosition ) { return true; }
public boolean isEmpty() { return false; }
public void onGroupCollapsed(int groupPosition)
{
m_closedLangs.add( m_langs[groupPosition] );
saveClosed();
}
public void onGroupExpanded(int groupPosition){
m_closedLangs.remove( m_langs[groupPosition] );
saveClosed();
}
public void registerDataSetObserver( DataSetObserver obs ){}
public void unregisterDataSetObserver( DataSetObserver obs ){}
protected XWListItem getSelChildView()
{
Assert.assertTrue( 1 == m_selDicts.size() );
return m_selDicts.iterator().next();
}
private void addToCache( int group, int child, XWListItem view )
{
if ( null == m_cache ) {
m_cache = new XWListItem[getGroupCount()][];
}
if ( null == m_cache[group] ) {
m_cache[group] = new XWListItem[getChildrenCount(group)];
}
Assert.assertTrue( null == m_cache[group][child] );
m_cache[group][child] = view;
}
}
protected DictsDelegate( ExpandableListActivity activity, Bundle savedInstanceState )
{
super( activity, savedInstanceState );
m_activity = activity;
init( savedInstanceState );
}
protected Dialog createDialog( int id )
{
OnClickListener lstnr, lstnr2;
Dialog dialog;
String message;
boolean doRemove = true;
DlgID dlgID = DlgID.values()[id];
switch( dlgID ) {
case MOVE_DICT:
final XWListItem[] selItems = getSelItems();
final int[] moveTo = { -1 };
message = m_activity.getString( R.string.move_dictf,
getJoinedNames( selItems ) );
OnClickListener newSelLstnr =
new OnClickListener() {
public void onClick( DialogInterface dlgi, int item ) {
moveTo[0] = item;
AlertDialog dlg = (AlertDialog)dlgi;
Button btn =
dlg.getButton( AlertDialog.BUTTON_POSITIVE );
btn.setEnabled( true );
}
};
lstnr = new OnClickListener() {
public void onClick( DialogInterface dlg, int item ) {
DictLoc toLoc = itemToRealLoc( moveTo[0] );
for ( XWListItem selItem : selItems ) {
DictLoc fromLoc = (DictLoc)selItem.getCached();
String name = selItem.getText();
if ( fromLoc == toLoc ) {
DbgUtils.logf( "not moving %s: same loc", name );
} else if ( DictUtils.moveDict( m_activity,
name, fromLoc,
toLoc ) ) {
selItem.setComment( m_locNames[toLoc.ordinal()] );
selItem.cache( toLoc );
selItem.invalidate();
DBUtils.dictsMoveInfo( m_activity, name,
fromLoc, toLoc );
} else {
DbgUtils.logf( "moveDict(%s) failed", name );
}
}
}
};
dialog = new AlertDialog.Builder( m_activity )
.setTitle( message )
.setSingleChoiceItems( makeDictDirItems(), moveTo[0],
newSelLstnr )
.setPositiveButton( R.string.button_move, lstnr )
.setNegativeButton( R.string.button_cancel, null )
.create();
break;
case SET_DEFAULT:
final XWListItem row = m_selDicts.iterator().next();
lstnr = new OnClickListener() {
public void onClick( DialogInterface dlg, int item ) {
if ( DialogInterface.BUTTON_NEGATIVE == item
|| DialogInterface.BUTTON_POSITIVE == item ) {
setDefault( row, R.string.key_default_dict );
}
if ( DialogInterface.BUTTON_NEGATIVE == item
|| DialogInterface.BUTTON_NEUTRAL == item ) {
setDefault( row, R.string.key_default_robodict );
}
}
};
String name = row.getText();
String lang = DictLangCache.getLangName( m_activity, name);
message = m_activity.getString( R.string.set_default_messagef, name, lang );
dialog = new AlertDialog.Builder( m_activity )
.setTitle( R.string.query_title )
.setMessage( message )
.setPositiveButton( R.string.button_default_human, lstnr )
.setNeutralButton( R.string.button_default_robot, lstnr )
.setNegativeButton( R.string.button_default_both, lstnr )
.create();
break;
case DICT_OR_DECLINE:
lstnr = new OnClickListener() {
public void onClick( DialogInterface dlg, int item ) {
Intent intent = m_activity.getIntent();
int lang = intent.getIntExtra( MultiService.LANG, -1 );
String name = intent.getStringExtra( MultiService.DICT );
m_launchedForMissing = true;
DictImportActivity
.downloadDictInBack( m_activity, lang,
name, DictsDelegate.this );
}
};
lstnr2 = new OnClickListener() {
public void onClick( DialogInterface dlg, int item ) {
m_activity.finish();
}
};
dialog = MultiService.missingDictDialog( m_activity,
m_activity.getIntent(),
lstnr, lstnr2 );
break;
default:
dialog = super.createDialog( id );
doRemove = false;
break;
}
if ( doRemove && null != dialog ) {
Utils.setRemoveOnDismiss( m_activity, dialog, dlgID );
}
return dialog;
} // createDialog
protected void prepareDialog( int id, Dialog dialog )
{
if ( DlgID.MOVE_DICT.ordinal() == id ) {
// The move button should always start out disabled
// because the selected location should be where it
// currently is.
((AlertDialog)dialog).getButton( AlertDialog.BUTTON_POSITIVE )
.setEnabled( false );
}
}
private void init( Bundle savedInstanceState )
{
m_closedLangs = new HashSet<String>();
String[] closed = XWPrefs.getClosedLangs( m_activity );
if ( null != closed ) {
for ( String str : closed ) {
m_closedLangs.add( str );
}
}
Resources res = m_activity.getResources();
m_locNames = res.getStringArray( R.array.loc_names );
m_factory = LayoutInflater.from( m_activity );
m_downloadStr = m_activity.getString( R.string.download_dicts );
m_activity.setContentView( R.layout.dict_browse );
m_expView = m_activity.getExpandableListView();
m_expView.setOnItemLongClickListener( this );
Button download = (Button)m_activity.findViewById( R.id.download );
if ( ABUtils.haveActionBar() ) {
download.setVisibility( View.GONE );
} else {
download.setOnClickListener( this );
}
mkListAdapter();
Intent intent = m_activity.getIntent();
if ( null != intent ) {
if ( MultiService.isMissingDictIntent( intent ) ) {
showDialog( DlgID.DICT_OR_DECLINE );
} else {
boolean downloadNow = intent.getBooleanExtra( DICT_DOLAUNCH, false );
if ( downloadNow ) {
int lang = intent.getIntExtra( DICT_LANG_EXTRA, 0 );
String name = intent.getStringExtra( DICT_NAME_EXTRA );
startDownload( lang, name );
}
downloadNewDict( intent );
}
}
m_origTitle = m_activity.getTitle();
} // onCreate
protected void onResume()
{
MountEventReceiver.register( this );
mkListAdapter();
expandGroups();
setTitleBar();
}
protected void onStop()
{
MountEventReceiver.unregister( this );
}
public void onClick( View view )
{
if ( view instanceof Button ) {
startDownload( 0, null );
} else {
XWListItem item = (XWListItem)view;
DictBrowseActivity.launch( m_activity, item.getText(),
(DictLoc)item.getCached() );
}
}
protected boolean onBackPressed()
{
boolean handled = 0 < m_selDicts.size();
if ( handled ) {
clearSelections();
}
return handled;
}
protected boolean onCreateOptionsMenu( Menu menu )
{
MenuInflater inflater = m_activity.getMenuInflater();
inflater.inflate( R.menu.dicts_menu, menu );
return true;
}
protected boolean onPrepareOptionsMenu( Menu menu )
{
int nSel = m_selDicts.size();
Utils.setItemVisible( menu, R.id.dicts_download,
0 == nSel && ABUtils.haveActionBar() );
Utils.setItemVisible( menu, R.id.dicts_select, 1 == nSel );
boolean allVolatile = selItemsVolatile();
Utils.setItemVisible( menu, R.id.dicts_move,
allVolatile && DictUtils.haveWriteableSD() );
Utils.setItemVisible( menu, R.id.dicts_delete, allVolatile );
return true;
}
protected boolean onOptionsItemSelected( MenuItem item )
{
boolean handled = true;
switch ( item.getItemId() ) {
case R.id.dicts_download:
startDownload( 0, null );
break;
case R.id.dicts_delete:
deleteSelected();
break;
case R.id.dicts_move:
showDialog( DlgID.MOVE_DICT );
break;
case R.id.dicts_select:
showDialog( DlgID.SET_DEFAULT );
break;
default:
handled = false;
}
return handled;
}
private void downloadNewDict( Intent intent )
{
int loci = intent.getIntExtra( UpdateCheckReceiver.NEW_DICT_LOC, 0 );
if ( 0 < loci ) {
String url =
intent.getStringExtra( UpdateCheckReceiver.NEW_DICT_URL );
DictImportActivity.downloadDictInBack( m_activity, url );
m_activity.finish();
}
}
private void setDefault( XWListItem view, int keyId )
{
SharedPreferences sp
= PreferenceManager.getDefaultSharedPreferences( m_activity );
SharedPreferences.Editor editor = sp.edit();
String key = m_activity.getString( keyId );
String name = view.getText();
editor.putString( key, name );
editor.commit();
}
//////////////////////////////////////////////////////////////////////
// OnItemLongClickListener interface
//////////////////////////////////////////////////////////////////////
public boolean onItemLongClick( AdapterView<?> parent, View view,
int position, long id ) {
boolean success = view instanceof SelectableItem.LongClickHandler;
if ( success ) {
((SelectableItem.LongClickHandler)view).longClicked();
}
return success;
}
private boolean selItemsVolatile()
{
boolean result = 0 < m_selDicts.size();
for ( Iterator<XWListItem> iter = m_selDicts.iterator();
result && iter.hasNext(); ) {
DictLoc loc = (DictLoc)iter.next().getCached();
if ( loc == DictLoc.BUILT_IN ) {
result = false;
}
}
return result;
}
private void deleteSelected()
{
XWListItem[] items = getSelItems();
String msg = m_activity.getString( R.string.confirm_delete_dictf,
getJoinedNames( items ) );
// When and what to warn about. First off, if there's another
// identical dict, simply confirm. Or if nobody's using this
// dict *and* it's not the last of a language that somebody's
// using, simply confirm. If somebody is using it, then we
// want different warnings depending on whether it's the last
// available dict in its language.
for ( XWListItem item : items ) {
String dict = item.getText();
if ( 1 < DictLangCache.getDictCount( m_activity, dict ) ) {
// there's another; do nothing
} else {
String newMsg = null;
int langcode = DictLangCache.getDictLangCode( m_activity, dict );
String langName = DictLangCache.getLangName( m_activity, langcode );
DictAndLoc[] langDals = DictLangCache.getDALsHaveLang( m_activity,
langcode );
int nUsingLang = DBUtils.countGamesUsingLang( m_activity, langcode );
if ( 1 == langDals.length ) { // last in this language?
if ( 0 < nUsingLang ) {
newMsg =
m_activity.getString( R.string.confirm_deleteonly_dictf,
dict, langName );
}
} else if ( 0 < DBUtils.countGamesUsingDict( m_activity, dict ) ) {
newMsg = m_activity.getString( R.string.confirm_deletemore_dictf,
langName );
}
if ( null != newMsg ) {
msg += "\n\n" + newMsg;
}
}
}
showConfirmThen( msg, R.string.button_delete, Action.DELETE_DICT_ACTION,
(Object)items );
} // deleteSelected
//////////////////////////////////////////////////////////////////////
// MountEventReceiver.SDCardNotifiee interface
//////////////////////////////////////////////////////////////////////
public void cardMounted( boolean nowMounted )
{
DbgUtils.logf( "DictsActivity.cardMounted(%b)", nowMounted );
// post so other SDCardNotifiee implementations get a chance
// to process first: avoid race conditions
post( new Runnable() {
public void run() {
mkListAdapter();
expandGroups();
}
} );
}
//////////////////////////////////////////////////////////////////////
// DlgDelegate.DlgClickNotify interface
//////////////////////////////////////////////////////////////////////
public void dlgButtonClicked( Action action, int which, Object[] params )
{
switch( action ) {
case DELETE_DICT_ACTION:
if ( DialogInterface.BUTTON_POSITIVE == which ) {
XWListItem[] items = (XWListItem[])params[0];
for ( XWListItem item : items ) {
String name = item.getText();
DictLoc loc = (DictLoc)item.getCached();
deleteDict( name, loc );
}
clearSelections();
}
break;
case DOWNLOAD_DICT_ACTION:
startDownload( (Intent)params[0] );
break;
default:
Assert.fail();
}
}
private DictLoc itemToRealLoc( int item )
{
item += DictLoc.INTERNAL.ordinal();
return DictLoc.values()[item];
}
private void deleteDict( String dict, DictLoc loc )
{
DictUtils.deleteDict( m_activity, dict, loc );
DictLangCache.inval( m_activity, dict, loc, false );
mkListAdapter();
expandGroups();
}
private void startDownload( int lang, String name )
{
Intent intent = mkDownloadIntent( m_activity, lang, name );
showNotAgainDlgThen( R.string.not_again_firefox,
R.string.key_na_firefox,
Action.DOWNLOAD_DICT_ACTION, intent );
}
private void startDownload( Intent downloadIntent )
{
try {
m_activity.startActivity( downloadIntent );
} catch ( android.content.ActivityNotFoundException anfe ) {
Utils.showToast( m_activity, R.string.no_download_warning );
}
}
private void mkListAdapter()
{
m_langs = DictLangCache.listLangs( m_activity );
Arrays.sort( m_langs );
m_adapter = new DictListAdapter( m_activity );
m_activity.setListAdapter( m_adapter );
m_selDicts = new HashSet<XWListItem>();
}
private void expandGroups()
{
for ( int ii = 0; ii < m_langs.length; ++ii ) {
boolean open = true;
String lang = m_langs[ii];
if ( ! m_closedLangs.contains( lang ) ) {
m_expView.expandGroup( ii );
}
}
}
private void saveClosed()
{
String[] asArray = m_closedLangs.toArray( new String[m_closedLangs.size()] );
XWPrefs.setClosedLangs( m_activity, asArray );
}
private void clearSelections()
{
if ( 0 < m_selDicts.size() ) {
XWListItem[] items = getSelItems();
m_selDicts.clear();
for ( XWListItem item : items ) {
item.setSelected( false );
}
}
}
private String getJoinedNames( XWListItem[] items )
{
String[] names = new String[items.length];
int ii = 0;
for ( XWListItem item : items ) {
names[ii++] = item.getText();
}
return TextUtils.join( ", ", names );
}
private XWListItem[] getSelItems()
{
XWListItem[] items = new XWListItem[m_selDicts.size()];
int indx = 0;
for ( Iterator<XWListItem> iter = m_selDicts.iterator();
iter.hasNext(); ) {
items[indx++] = iter.next();
}
return items;
}
private void setTitleBar()
{
int nSels = m_selDicts.size();
if ( 0 < nSels ) {
m_activity.setTitle( m_activity.getString( R.string.sel_itemsf,
nSels ) );
} else {
m_activity.setTitle( m_origTitle );
}
}
private String[] makeDictDirItems()
{
boolean showDownload = DictUtils.haveDownloadDir( m_activity );
int nItems = showDownload ? 3 : 2;
int nextI = 0;
String[] items = new String[nItems];
for ( int ii = 0; ii < 3; ++ii ) {
DictLoc loc = itemToRealLoc(ii);
if ( !showDownload && DictLoc.DOWNLOAD == loc ) {
continue;
}
items[nextI++] = m_locNames[loc.ordinal()];
}
return items;
}
private static Intent mkDownloadIntent( Context context, String dict_url )
{
Uri uri = Uri.parse( dict_url );
Intent intent = new Intent( Intent.ACTION_VIEW, uri );
intent.setFlags( Intent.FLAG_ACTIVITY_NEW_TASK );
return intent;
}
private static Intent mkDownloadIntent( Context context,
int lang, String dict )
{
String dict_url = Utils.makeDictUrl( context, lang, dict );
return mkDownloadIntent( context, dict_url );
}
public static void launchAndDownload( Activity activity, int lang,
String name )
{
Intent intent = new Intent( activity, DictsActivity.class );
intent.putExtra( DICT_DOLAUNCH, true );
if ( lang > 0 ) {
intent.putExtra( DICT_LANG_EXTRA, lang );
}
if ( null != name ) {
Assert.assertTrue( lang != 0 );
intent.putExtra( DICT_NAME_EXTRA, name );
}
activity.startActivity( intent );
}
public static void launchAndDownload( Activity activity, int lang )
{
launchAndDownload( activity, lang, null );
}
public static void launchAndDownload( Activity activity )
{
launchAndDownload( activity, 0, null );
}
// DictImportActivity.DownloadFinishedListener interface
public void downloadFinished( String name, final boolean success )
{
if ( m_launchedForMissing ) {
post( new Runnable() {
public void run() {
if ( success ) {
Intent intent = m_activity.getIntent();
if ( MultiService.returnOnDownload( m_activity,
intent ) ) {
m_activity.finish();
}
} else {
Utils.showToast( m_activity,
R.string.download_failed );
}
}
} );
}
}
// SelectableItem interface
public void itemClicked( SelectableItem.LongClickHandler clicked,
GameSummary summary )
{
DbgUtils.logf( "itemClicked not implemented" );
}
public void itemToggled( SelectableItem.LongClickHandler toggled,
boolean selected )
{
XWListItem dictView = (XWListItem)toggled;
if ( selected ) {
m_selDicts.add( dictView );
} else {
m_selDicts.remove( dictView );
}
ABUtils.invalidateOptionsMenuIf( m_activity );
setTitleBar();
}
public boolean getSelected( SelectableItem.LongClickHandler obj )
{
XWListItem dictView = (XWListItem)obj;
return m_selDicts.contains( dictView );
}
}

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/* /*
* Copyright 2010 by Eric House (xwords@eehouse.org). All rights * Copyright 2010 by Eric House (xwords@eehouse.org). All rights
* reserved. * reserved.
@ -40,7 +40,7 @@ public class DispatchNotify extends Activity {
Uri data = getIntent().getData(); Uri data = getIntent().getData();
if ( null != data ) { // relay invite redirected URL case if ( null != data ) { // relay invite redirected URL case
GamesList.openGame( this, data ); GamesListActivity.openGame( this, data );
} }
finish(); finish();

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/* /*
* Copyright 2009 - 2012 by Eric House (xwords@eehouse.org). All * Copyright 2009 - 2012 by Eric House (xwords@eehouse.org). All
* rights reserved. * rights reserved.
@ -39,25 +39,79 @@ import junit.framework.Assert;
public class DlgDelegate { public class DlgDelegate {
public static final int DIALOG_ABOUT = 1; public static enum Action {
public static final int DIALOG_OKONLY = 2; SKIP_CALLBACK,
public static final int DIALOG_NOTAGAIN = 3;
public static final int CONFIRM_THEN = 4; // GameListDelegate
public static final int INVITE_CHOICES_THEN = 5; RESET_GAMES,
public static final int DLG_DICTGONE = 6; SYNC_MENU,
public static final int DIALOG_LAST = DLG_DICTGONE; NEW_FROM,
DELETE_GAMES,
DELETE_GROUPS,
OPEN_GAME,
CLEAR_SELS,
NEW_NET_GAME,
// BoardDelegate
UNDO_LAST_ACTION,
LAUNCH_INVITE_ACTION,
SYNC_ACTION,
COMMIT_ACTION,
SHOW_EXPL_ACTION,
PREV_HINT_ACTION,
NEXT_HINT_ACTION,
JUGGLE_ACTION,
FLIP_ACTION,
ZOOM_ACTION,
UNDO_ACTION,
CHAT_ACTION,
START_TRADE_ACTION,
LOOKUP_ACTION,
BUTTON_BROWSE_ACTION,
VALUES_ACTION,
BT_PICK_ACTION,
SMS_PICK_ACTION,
SMS_CONFIG_ACTION,
BUTTON_BROWSEALL_ACTION,
// Dict Browser
FINISH_ACTION,
DELETE_DICT_ACTION,
DOWNLOAD_DICT_ACTION,
// Game configs
LOCKED_CHANGE_ACTION,
// New Game
NEW_GAME_ACTION,
// SMS invite
CLEAR_ACTION,
USE_IMMOBILE_ACTION,
POST_WARNING_ACTION,
// Study list
SL_CLEAR_ACTION,
SL_COPY_ACTION,
__LAST
}
public static final int SMS_BTN = AlertDialog.BUTTON_POSITIVE; public static final int SMS_BTN = AlertDialog.BUTTON_POSITIVE;
public static final int EMAIL_BTN = AlertDialog.BUTTON_NEGATIVE; public static final int EMAIL_BTN = AlertDialog.BUTTON_NEGATIVE;
public static final int NFC_BTN = AlertDialog.BUTTON_NEUTRAL; public static final int NFC_BTN = AlertDialog.BUTTON_NEUTRAL;
public static final int DISMISS_BUTTON = 0; public static final int DISMISS_BUTTON = 0;
public static final int SKIP_CALLBACK = -1;
private static final String IDS = "IDS"; private static final String IDS = "IDS";
private static final String STATE_KEYF = "STATE_%d"; private static final String STATE_KEYF = "STATE_%d";
public interface DlgClickNotify { public interface DlgClickNotify {
void dlgButtonClicked( int id, int button, Object[] params ); void dlgButtonClicked( Action action, int button, Object[] params );
}
public interface HasDlgDelegate {
void showOKOnlyDialog( int msgID );
void showOKOnlyDialog( String msg );
void showNotAgainDlgThen( int msgID, int prefsKey, Action action );
} }
private Activity m_activity; private Activity m_activity;
@ -66,7 +120,7 @@ public class DlgDelegate {
private ProgressDialog m_progress; private ProgressDialog m_progress;
private Handler m_handler; private Handler m_handler;
private HashMap<Integer, DlgState> m_dlgStates; private HashMap<DlgID, DlgState> m_dlgStates;
public DlgDelegate( Activity activity, DlgClickNotify callback, public DlgDelegate( Activity activity, DlgClickNotify callback,
Bundle bundle ) Bundle bundle )
@ -74,7 +128,7 @@ public class DlgDelegate {
m_activity = activity; m_activity = activity;
m_clickCallback = callback; m_clickCallback = callback;
m_handler = new Handler(); m_handler = new Handler();
m_dlgStates = new HashMap<Integer,DlgState>(); m_dlgStates = new HashMap<DlgID,DlgState>();
if ( null != bundle ) { if ( null != bundle ) {
int[] ids = bundle.getIntArray( IDS ); int[] ids = bundle.getIntArray( IDS );
@ -93,34 +147,44 @@ public class DlgDelegate {
Iterator<DlgState> iter = m_dlgStates.values().iterator(); Iterator<DlgState> iter = m_dlgStates.values().iterator();
while ( iter.hasNext() ) { while ( iter.hasNext() ) {
DlgState state = iter.next(); DlgState state = iter.next();
String key = String.format( STATE_KEYF, state.m_id ); int id = state.m_id.ordinal();
String key = String.format( STATE_KEYF, id );
outState.putParcelable( key, state ); outState.putParcelable( key, state );
ids[indx++] = state.m_id; ids[indx++] = id;
} }
} }
outState.putIntArray( IDS, ids ); outState.putIntArray( IDS, ids );
} }
public Dialog onCreateDialog( int id ) protected void showDialog( DlgID dlgID )
{ {
// DbgUtils.logf("onCreateDialog(id=%d)", id ); m_activity.showDialog( dlgID.ordinal() );
}
public Dialog createDialog( int id )
{
// DbgUtils.logf("createDialog(id=%d)", id );
Dialog dialog = null; Dialog dialog = null;
DlgState state = findForID( id ); DlgID dlgID = DlgID.values()[id];
switch( id ) { DlgState state = findForID( dlgID );
switch( dlgID ) {
case LOOKUP:
dialog = createLookupDialog();
break;
case DIALOG_ABOUT: case DIALOG_ABOUT:
dialog = createAboutDialog(); dialog = createAboutDialog();
break; break;
case DIALOG_OKONLY: case DIALOG_OKONLY:
dialog = createOKDialog( state, id ); dialog = createOKDialog( state, dlgID );
break; break;
case DIALOG_NOTAGAIN: case DIALOG_NOTAGAIN:
dialog = createNotAgainDialog( state, id ); dialog = createNotAgainDialog( state, dlgID );
break; break;
case CONFIRM_THEN: case CONFIRM_THEN:
dialog = createConfirmThenDialog( state, id ); dialog = createConfirmThenDialog( state, dlgID );
break; break;
case INVITE_CHOICES_THEN: case INVITE_CHOICES_THEN:
dialog = createInviteChoicesDialog( state, id ); dialog = createInviteChoicesDialog( state, dlgID );
break; break;
case DLG_DICTGONE: case DLG_DICTGONE:
dialog = createDictGoneDialog(); dialog = createDictGoneDialog();
@ -131,52 +195,52 @@ public class DlgDelegate {
public void showOKOnlyDialog( String msg ) public void showOKOnlyDialog( String msg )
{ {
showOKOnlyDialog( msg, SKIP_CALLBACK ); showOKOnlyDialog( msg, Action.SKIP_CALLBACK );
} }
public void showOKOnlyDialog( String msg, int callbackID ) public void showOKOnlyDialog( String msg, Action action )
{ {
// Assert.assertNull( m_dlgStates ); // Assert.assertNull( m_dlgStates );
DlgState state = new DlgState( DIALOG_OKONLY, msg, callbackID ); DlgState state = new DlgState( DlgID.DIALOG_OKONLY, msg, action );
addState( state ); addState( state );
m_activity.showDialog( DIALOG_OKONLY ); m_activity.showDialog( DlgID.DIALOG_OKONLY.ordinal() );
} }
public void showOKOnlyDialog( int msgID ) public void showOKOnlyDialog( int msgID )
{ {
showOKOnlyDialog( m_activity.getString( msgID ), SKIP_CALLBACK ); showOKOnlyDialog( m_activity.getString( msgID ), Action.SKIP_CALLBACK );
} }
public void showDictGoneFinish() public void showDictGoneFinish()
{ {
m_activity.showDialog( DLG_DICTGONE ); m_activity.showDialog( DlgID.DLG_DICTGONE.ordinal() );
} }
public void showAboutDialog() public void showAboutDialog()
{ {
m_activity.showDialog( DIALOG_ABOUT ); m_activity.showDialog( DlgID.DIALOG_ABOUT.ordinal() );
} }
public void showNotAgainDlgThen( int msgID, int prefsKey, public void showNotAgainDlgThen( int msgID, int prefsKey,
final int callbackID, final Action action,
final Object[] params ) final Object[] params )
{ {
showNotAgainDlgThen( m_activity.getString( msgID ), prefsKey, showNotAgainDlgThen( m_activity.getString( msgID ), prefsKey,
callbackID, params ); action, params );
} }
public void showNotAgainDlgThen( String msg, int prefsKey, public void showNotAgainDlgThen( String msg, int prefsKey,
final int callbackID, final Action action,
final Object[] params ) final Object[] params )
{ {
if ( XWPrefs.getPrefsBoolean( m_activity, prefsKey, false ) ) { if ( XWPrefs.getPrefsBoolean( m_activity, prefsKey, false ) ) {
// If it's set, do the action without bothering with the // If it's set, do the action without bothering with the
// dialog // dialog
if ( SKIP_CALLBACK != callbackID ) { if ( Action.SKIP_CALLBACK != action ) {
post( new Runnable() { post( new Runnable() {
public void run() { public void run() {
m_clickCallback m_clickCallback
.dlgButtonClicked( callbackID, .dlgButtonClicked( action,
AlertDialog.BUTTON_POSITIVE, AlertDialog.BUTTON_POSITIVE,
params ); params );
} }
@ -184,59 +248,72 @@ public class DlgDelegate {
} }
} else { } else {
DlgState state = DlgState state =
new DlgState( DIALOG_NOTAGAIN, msg, callbackID, prefsKey, new DlgState( DlgID.DIALOG_NOTAGAIN, msg, action, prefsKey,
params ); params );
addState( state ); addState( state );
m_activity.showDialog( DIALOG_NOTAGAIN ); m_activity.showDialog( DlgID.DIALOG_NOTAGAIN.ordinal() );
} }
} }
public void showNotAgainDlgThen( int msgID, int prefsKey, public void showNotAgainDlgThen( int msgID, int prefsKey,
int callbackID ) Action action)
{ {
showNotAgainDlgThen( msgID, prefsKey, callbackID, null ); showNotAgainDlgThen( msgID, prefsKey, action, null );
} }
public void showNotAgainDlgThen( int msgID, int prefsKey ) public void showNotAgainDlgThen( int msgID, int prefsKey )
{ {
showNotAgainDlgThen( msgID, prefsKey, SKIP_CALLBACK ); showNotAgainDlgThen( msgID, prefsKey, Action.SKIP_CALLBACK );
} }
public void showConfirmThen( String msg, int callbackID ) public void showConfirmThen( String msg, Action action )
{ {
showConfirmThen( msg, R.string.button_ok, callbackID, null ); showConfirmThen( msg, R.string.button_ok, action, null );
} }
public void showConfirmThen( String msg, int callbackID, Object[] params ) public void showConfirmThen( int msgID, Action action )
{ {
showConfirmThen( msg, R.string.button_ok, callbackID, params ); showConfirmThen( m_activity.getString( msgID ),
R.string.button_ok, action, null );
} }
public void showConfirmThen( String msg, int posButton, int callbackID ) public void showConfirmThen( String msg, Action action, Object[] params )
{ {
showConfirmThen( msg, posButton, callbackID, null ); showConfirmThen( msg, R.string.button_ok, action, params );
} }
public void showConfirmThen( String msg, int posButton, int callbackID, public void showConfirmThen( String msg, int posButton, Action action )
{
showConfirmThen( msg, posButton, action, null );
}
public void showConfirmThen( int msg, int posButton, Action action,
Object[] params ) Object[] params )
{ {
DlgState state = new DlgState( CONFIRM_THEN, msg, posButton, showConfirmThen( m_activity.getString( msg ), posButton, action,
callbackID, 0, params ); params );
addState( state );
m_activity.showDialog( CONFIRM_THEN );
} }
public void showInviteChoicesThen( final int callbackID ) public void showConfirmThen( String msg, int posButton, Action action,
Object[] params )
{
DlgState state = new DlgState( DlgID.CONFIRM_THEN, msg, posButton,
action, 0, params );
addState( state );
m_activity.showDialog( DlgID.CONFIRM_THEN.ordinal() );
}
public void showInviteChoicesThen( final Action action )
{ {
if ( Utils.deviceSupportsSMS( m_activity ) if ( Utils.deviceSupportsSMS( m_activity )
|| NFCUtils.nfcAvail( m_activity )[0] ) { || NFCUtils.nfcAvail( m_activity )[0] ) {
DlgState state = new DlgState( INVITE_CHOICES_THEN, callbackID ); DlgState state = new DlgState( DlgID.INVITE_CHOICES_THEN, action );
addState( state ); addState( state );
m_activity.showDialog( INVITE_CHOICES_THEN ); m_activity.showDialog( DlgID.INVITE_CHOICES_THEN.ordinal() );
} else { } else {
post( new Runnable() { post( new Runnable() {
public void run() { public void run() {
m_clickCallback.dlgButtonClicked( callbackID, EMAIL_BTN, m_clickCallback.dlgButtonClicked( action, EMAIL_BTN,
null ); null );
} }
}); });
@ -253,13 +330,11 @@ public class DlgDelegate {
} }
} }
public void launchLookup( String[] words, int lang, boolean forceList ) public void launchLookup( String[] words, int lang, boolean noStudyOption )
{ {
Intent intent = new Intent( m_activity, LookupActivity.class ); Bundle params = LookupAlert.makeParams( words, lang, noStudyOption );
intent.putExtra( LookupActivity.WORDS, words ); addState( new DlgState( DlgID.LOOKUP, new Object[]{params} ) );
intent.putExtra( LookupActivity.LANG, lang ); m_activity.showDialog( DlgID.LOOKUP.ordinal() );
m_activity.startActivity( intent );
} }
public void startProgress( int id ) public void startProgress( int id )
@ -315,7 +390,7 @@ public class DlgDelegate {
post( new Runnable() { post( new Runnable() {
public void run() { public void run() {
if ( asDlg ) { if ( asDlg ) {
showOKOnlyDialog( fmsg, SKIP_CALLBACK ); showOKOnlyDialog( fmsg, Action.SKIP_CALLBACK );
} else { } else {
DbgUtils.showf( m_activity, fmsg ); DbgUtils.showf( m_activity, fmsg );
} }
@ -330,7 +405,8 @@ public class DlgDelegate {
TextView vers = (TextView)view.findViewById( R.id.version_string ); TextView vers = (TextView)view.findViewById( R.id.version_string );
vers.setText( String.format( m_activity.getString(R.string.about_versf), vers.setText( String.format( m_activity.getString(R.string.about_versf),
m_activity.getString(R.string.app_version), m_activity.getString(R.string.app_version),
BuildConstants.GIT_REV ) ); BuildConstants.GIT_REV,
BuildConstants.BUILD_STAMP ) );
TextView xlator = (TextView)view.findViewById( R.id.about_xlator ); TextView xlator = (TextView)view.findViewById( R.id.about_xlator );
String str = m_activity.getString( R.string.xlator ); String str = m_activity.getString( R.string.xlator );
@ -344,7 +420,7 @@ public class DlgDelegate {
.setIcon( R.drawable.icon48x48 ) .setIcon( R.drawable.icon48x48 )
.setTitle( R.string.app_name ) .setTitle( R.string.app_name )
.setView( view ) .setView( view )
.setPositiveButton( R.string.changes_button, .setNegativeButton( R.string.changes_button,
new OnClickListener() { new OnClickListener() {
@Override @Override
public void onClick( DialogInterface dlg, public void onClick( DialogInterface dlg,
@ -353,22 +429,30 @@ public class DlgDelegate {
FirstRunDialog.show( m_activity ); FirstRunDialog.show( m_activity );
} }
} ) } )
.setPositiveButton( R.string.button_ok, null )
.create(); .create();
} }
private Dialog createOKDialog( DlgState state, int id ) private Dialog createLookupDialog()
{
DlgState state = findForID( DlgID.LOOKUP );
Bundle bundle = (Bundle)state.m_params[0];
return LookupAlert.createDialog( m_activity, bundle );
}
private Dialog createOKDialog( DlgState state, DlgID dlgID )
{ {
Dialog dialog = new AlertDialog.Builder( m_activity ) Dialog dialog = new AlertDialog.Builder( m_activity )
.setTitle( R.string.info_title ) .setTitle( R.string.info_title )
.setMessage( state.m_msg ) .setMessage( state.m_msg )
.setPositiveButton( R.string.button_ok, null ) .setPositiveButton( R.string.button_ok, null )
.create(); .create();
dialog = setCallbackDismissListener( dialog, state, id ); dialog = setCallbackDismissListener( dialog, state, dlgID );
return dialog; return dialog;
} }
private Dialog createNotAgainDialog( final DlgState state, int id ) private Dialog createNotAgainDialog( final DlgState state, DlgID dlgID )
{ {
OnClickListener lstnr_p = mkCallbackClickListener( state ); OnClickListener lstnr_p = mkCallbackClickListener( state );
@ -377,9 +461,9 @@ public class DlgDelegate {
public void onClick( DialogInterface dlg, int item ) { public void onClick( DialogInterface dlg, int item ) {
XWPrefs.setPrefsBoolean( m_activity, state.m_prefsKey, XWPrefs.setPrefsBoolean( m_activity, state.m_prefsKey,
true ); true );
if ( SKIP_CALLBACK != state.m_cbckID ) { if ( Action.SKIP_CALLBACK != state.m_action ) {
m_clickCallback. m_clickCallback.
dlgButtonClicked( state.m_cbckID, dlgButtonClicked( state.m_action,
AlertDialog.BUTTON_POSITIVE, AlertDialog.BUTTON_POSITIVE,
state.m_params ); state.m_params );
} }
@ -393,10 +477,10 @@ public class DlgDelegate {
.setNegativeButton( R.string.button_notagain, lstnr_n ) .setNegativeButton( R.string.button_notagain, lstnr_n )
.create(); .create();
return setCallbackDismissListener( dialog, state, id ); return setCallbackDismissListener( dialog, state, dlgID );
} // createNotAgainDialog } // createNotAgainDialog
private Dialog createConfirmThenDialog( DlgState state, int id ) private Dialog createConfirmThenDialog( DlgState state, DlgID dlgID )
{ {
OnClickListener lstnr = mkCallbackClickListener( state ); OnClickListener lstnr = mkCallbackClickListener( state );
@ -407,10 +491,10 @@ public class DlgDelegate {
.setNegativeButton( R.string.button_cancel, lstnr ) .setNegativeButton( R.string.button_cancel, lstnr )
.create(); .create();
return setCallbackDismissListener( dialog, state, id ); return setCallbackDismissListener( dialog, state, dlgID );
} }
private Dialog createInviteChoicesDialog( DlgState state, int id ) private Dialog createInviteChoicesDialog( DlgState state, DlgID dlgID )
{ {
OnClickListener lstnr = mkCallbackClickListener( state ); OnClickListener lstnr = mkCallbackClickListener( state );
@ -437,7 +521,7 @@ public class DlgDelegate {
builder.setNeutralButton( R.string.button_nfc, lstnr ); builder.setNeutralButton( R.string.button_nfc, lstnr );
} }
return setCallbackDismissListener( builder.create(), state, id ); return setCallbackDismissListener( builder.create(), state, dlgID );
} }
private Dialog createDictGoneDialog() private Dialog createDictGoneDialog()
@ -462,8 +546,8 @@ public class DlgDelegate {
OnClickListener cbkOnClickLstnr; OnClickListener cbkOnClickLstnr;
cbkOnClickLstnr = new OnClickListener() { cbkOnClickLstnr = new OnClickListener() {
public void onClick( DialogInterface dlg, int button ) { public void onClick( DialogInterface dlg, int button ) {
if ( SKIP_CALLBACK != state.m_cbckID ) { if ( Action.SKIP_CALLBACK != state.m_action ) {
m_clickCallback.dlgButtonClicked( state.m_cbckID, m_clickCallback.dlgButtonClicked( state.m_action,
button, button,
state.m_params ); state.m_params );
} }
@ -474,14 +558,15 @@ public class DlgDelegate {
private Dialog setCallbackDismissListener( final Dialog dialog, private Dialog setCallbackDismissListener( final Dialog dialog,
final DlgState state, final DlgState state,
final int id ) DlgID dlgID )
{ {
final int id = dlgID.ordinal();
DialogInterface.OnDismissListener cbkOnDismissLstnr DialogInterface.OnDismissListener cbkOnDismissLstnr
= new DialogInterface.OnDismissListener() { = new DialogInterface.OnDismissListener() {
public void onDismiss( DialogInterface di ) { public void onDismiss( DialogInterface di ) {
dropState( state ); dropState( state );
if ( SKIP_CALLBACK != state.m_cbckID ) { if ( Action.SKIP_CALLBACK != state.m_action ) {
m_clickCallback.dlgButtonClicked( state.m_cbckID, m_clickCallback.dlgButtonClicked( state.m_action,
DISMISS_BUTTON, DISMISS_BUTTON,
state.m_params ); state.m_params );
} }
@ -493,9 +578,9 @@ public class DlgDelegate {
return dialog; return dialog;
} }
private DlgState findForID( int id ) private DlgState findForID( DlgID dlgID )
{ {
DlgState state = m_dlgStates.get( id ); DlgState state = m_dlgStates.get( dlgID );
// DbgUtils.logf( "findForID(%d)=>%H", id, state ); // DbgUtils.logf( "findForID(%d)=>%H", id, state );
return state; return state;
} }

View file

@ -0,0 +1,71 @@
/* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/*
* Copyright 2014 by Eric House (xwords@eehouse.org). All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.eehouse.android.xw4;
public enum DlgID {
NONE
, LOOKUP
, CHANGE_GROUP
, CONFIRM_CHANGE
, CONFIRM_CHANGE_PLAY
, CONFIRM_THEN
, DIALOG_ABOUT
, DIALOG_NOTAGAIN
, DIALOG_OKONLY
, DICT_OR_DECLINE
, DLG_CONNSTAT
, DLG_DELETED
, DLG_DICTGONE
, DLG_INVITE
, DLG_OKONLY
, ENABLE_NFC
, EXPLAIN_TITLE
, FORCE_REMOTE
, GAME_OVER
, GET_NAME
, GET_NUMBER
, INVITE_CHOICES_THEN
, MOVE_DICT
, NAME_GAME
, NEW_GROUP
, NO_NAME_FOUND
, PLAYER_EDIT
, CONFIRM_SMS
, QUERY_ENDGAME
, RENAME_GAME
, RENAME_GROUP
, REVERT_ALL
, REVERT_COLORS
, SET_DEFAULT
, SHOW_SUBST
, WARN_NODICT
, WARN_NODICT_NEW
, WARN_NODICT_SUBST
, DLG_BADWORDS_BLK
, QUERY_REQUEST_BLK
, QUERY_INFORM_BLK
, PICK_TILE_REQUESTBLANK_BLK
, ASK_PASSWORD_BLK
, DLG_RETRY
, DLG_SCORES
, PICK_TILE_REQUESTTRAY_BLK
, DLG_USEDICT
, DLG_GETDICT
}

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/* /*
* Copyright 2009 - 2013 by Eric House (xwords@eehouse.org). All * Copyright 2009 - 2013 by Eric House (xwords@eehouse.org). All
* rights reserved. * rights reserved.
@ -20,54 +20,61 @@
package org.eehouse.android.xw4; package org.eehouse.android.xw4;
import org.eehouse.android.xw4.DlgDelegate.Action;
import android.os.Parcelable; import android.os.Parcelable;
import android.os.Parcel; import android.os.Parcel;
public class DlgState implements Parcelable { public class DlgState implements Parcelable {
public int m_id; public DlgID m_id;
public String m_msg; public String m_msg;
public int m_posButton; public int m_posButton;
public int m_cbckID = 0; public Action m_action = null;
public int m_prefsKey; public int m_prefsKey;
public Object[] m_params; public Object[] m_params;
public DlgState( int id, String msg, int cbckID ) public DlgState( DlgID dlgID, String msg, Action action )
{ {
this( id, msg, R.string.button_ok, cbckID, 0 ); this( dlgID, msg, R.string.button_ok, action, 0 );
} }
public DlgState( int id, String msg, int cbckID, int prefsKey ) public DlgState( DlgID dlgID, String msg, Action action, int prefsKey )
{ {
this( id, msg, R.string.button_ok, cbckID, prefsKey ); this( dlgID, msg, R.string.button_ok, action, prefsKey );
} }
public DlgState( int id, String msg, int cbckID, int prefsKey, public DlgState( DlgID dlgID, String msg, Action action, int prefsKey,
Object[] params ) Object[] params )
{ {
this( id, msg, R.string.button_ok, cbckID, prefsKey ); this( dlgID, msg, R.string.button_ok, action, prefsKey );
m_params = params; m_params = params;
} }
public DlgState( int id, String msg, int posButton, public DlgState( DlgID dlgID, String msg, int posButton,
int cbckID, int prefsKey ) Action action, int prefsKey )
{ {
this( id, msg, posButton, cbckID, prefsKey, null ); this( dlgID, msg, posButton, action, prefsKey, null );
} }
public DlgState( int id, String msg, int posButton, public DlgState( DlgID dlgID, String msg, int posButton,
int cbckID, int prefsKey, Object[] params ) Action action, int prefsKey, Object[] params )
{ {
m_id = id; m_id = dlgID;
m_msg = msg; m_msg = msg;
m_posButton = posButton; m_posButton = posButton;
m_cbckID = cbckID; m_action = action;
m_prefsKey = prefsKey; m_prefsKey = prefsKey;
m_params = params; m_params = params;
} }
public DlgState( int id, int cbckID ) public DlgState( DlgID dlgID, Action action )
{ {
this( id, null, 0, cbckID, 0 ); this( dlgID, null, 0, action, 0 );
}
public DlgState( DlgID dlgID, Object[] params )
{
this( dlgID, null, 0, null, 0, params );
} }
public int describeContents() { public int describeContents() {
@ -75,9 +82,9 @@ public class DlgState implements Parcelable {
} }
public void writeToParcel( Parcel out, int flags ) { public void writeToParcel( Parcel out, int flags ) {
out.writeInt( m_id ); out.writeInt( m_id.ordinal() );
out.writeInt( m_posButton ); out.writeInt( m_posButton );
out.writeInt( m_cbckID ); out.writeInt( null == m_action ? -1 : m_action.ordinal() );
out.writeInt( m_prefsKey ); out.writeInt( m_prefsKey );
out.writeString( m_msg ); out.writeString( m_msg );
} }
@ -85,12 +92,13 @@ public class DlgState implements Parcelable {
public static final Parcelable.Creator<DlgState> CREATOR public static final Parcelable.Creator<DlgState> CREATOR
= new Parcelable.Creator<DlgState>() { = new Parcelable.Creator<DlgState>() {
public DlgState createFromParcel(Parcel in) { public DlgState createFromParcel(Parcel in) {
int id = in.readInt(); DlgID id = DlgID.values()[in.readInt()];
int posButton = in.readInt(); int posButton = in.readInt();
int cbckID = in.readInt(); int tmp = in.readInt();
Action action = 0 > tmp ? null : Action.values()[tmp];
int prefsKey = in.readInt(); int prefsKey = in.readInt();
String msg = in.readString(); String msg = in.readString();
return new DlgState( id, msg, posButton, cbckID, prefsKey ); return new DlgState( id, msg, posButton, action, prefsKey );
} }
public DlgState[] newArray(int size) { public DlgState[] newArray(int size) {

View file

@ -0,0 +1,47 @@
/* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/*
* Copyright 2009-2014 by Eric House (xwords@eehouse.org). All
* rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.eehouse.android.xw4;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.view.View;
public class DrawSelDelegate {
private View m_view;
private Drawable m_origDrawable;
private static ColorDrawable s_selDrawable =
new ColorDrawable( XWApp.SEL_COLOR );
protected DrawSelDelegate( View view )
{
m_view = view;
}
protected void showSelected( boolean selected )
{
if ( selected ) {
m_origDrawable = m_view.getBackground();
m_view.setBackgroundDrawable( s_selDrawable );
} else {
m_view.setBackgroundDrawable( m_origDrawable );
}
}
}

Some files were not shown because too many files have changed in this diff Show more