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
*.~?~
*~
/gitignored
TAGS
core

View file

@ -4,4 +4,15 @@ tags:
-o -name '*.h' -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
gen
proguard.cfg
proguard-project.txt
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. -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.eehouse.android.xw4bt"
android:versionCode="68"
android:versionCode="72"
android:versionName="@string/app_version"
>
@ -45,6 +45,7 @@
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.RECEIVE_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_ADMIN" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
@ -129,6 +130,10 @@
android:theme="@android:style/Theme.Dialog"
/>
<activity android:name="StudyList"
android:configChanges="keyboardHidden|orientation|screenSize"
/>
<receiver android:name="RelayReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
@ -144,7 +149,6 @@
<activity android:name="DispatchNotify">
<intent-filter>
<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.BROWSABLE" />
<data android:scheme="newxwgame"/>

View file

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

View file

@ -68,6 +68,7 @@ COMMON_SRC_FILES += \
$(COMMON_PATH)/tray.c \
$(COMMON_PATH)/dictnry.c \
$(COMMON_PATH)/dictiter.c \
$(COMMON_PATH)/dictmgr.c \
$(COMMON_PATH)/mscore.c \
$(COMMON_PATH)/vtabmgr.c \
$(COMMON_PATH)/strutils.c \
@ -90,5 +91,10 @@ LOCAL_LDLIBS := -L${SYSROOT}/usr/lib -llog -lz
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_PATH :=

View file

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

View file

@ -14,3 +14,7 @@ reset__gen.png
save__gen.png
send__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
send__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
send__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
confirm_sms.xml
game_list_group.xml
studylist.xml

View file

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

View file

@ -78,3 +78,10 @@ XWPrefs.java
XWService.java
XWSumListPreference.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
bin
gen
libs
proguard.cfg
obj

View file

@ -22,19 +22,48 @@
to come from a domain that you own or have control over. -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.eehouse.android.xw4dbg"
android:versionCode="34"
android:versionCode="73"
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.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.VIBRATE" />
<!-- <uses-permission android:name="android.permission.RECEIVE_SMS" /> -->
<!-- <uses-permission android:name="android.permission.SEND_SMS" /> -->
<uses-permission android:name="android.permission.RECEIVE_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"
android:label="@string/app_name"
@ -44,26 +73,39 @@
<activity android:name="GamesList"
android:label="@string/app_name"
android:launchMode="standard"
android:configChanges="keyboardHidden|orientation"
android:configChanges="keyboardHidden|orientation|screenSize"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</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 android:name="DictsActivity"
android:label="@string/title_dicts_list"
android:configChanges="keyboardHidden|orientation"
android:configChanges="keyboardHidden|orientation|screenSize"
/>
<activity android:name="NewGameActivity"
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"
android:screenOrientation="sensor"
android:configChanges="keyboardHidden|orientation"
android:configChanges="keyboardHidden|orientation|screenSize"
>
<intent-filter>
<action android:name="android.intent.action.EDIT" />
@ -73,15 +115,22 @@
<activity android:name="PrefsActivity"
android:label="@string/title_prefs"
android:screenOrientation="sensor"
>
</activity>
android:configChanges="keyboardHidden|orientation|screenSize"
/>
<activity android:name="BoardActivity"
android:theme="@android:style/Theme.Light"
android:screenOrientation="portrait"
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">
<intent-filter>
@ -89,15 +138,37 @@
</intent-filter>
</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>
<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.BROWSABLE" />
<data android:scheme="newxwgame"/>
</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>
<!-- downloading dicts -->
@ -119,10 +190,10 @@
<activity android:name="RelayGameActivity"/>
<activity android:name="DictBrowseActivity"
android:configChanges="keyboardHidden|orientation"
android:configChanges="keyboardHidden|orientation|screenSize"
/>
<activity android:name="ChatActivity"
android:configChanges="keyboardHidden|orientation"
android:configChanges="keyboardHidden|orientation|screenSize"
/>
<service android:name="RelayService"/>
@ -138,14 +209,24 @@
</intent-filter>
</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"> -->
<!-- <intent-filter android:priority="10"> -->
<!-- <action android:name="android.intent.action.DATA_SMS_RECEIVED" /> -->
<!-- <data android:scheme="sms" /> -->
<!-- <data android:port="50009" /> -->
<!-- </intent-filter> -->
<!-- </receiver> -->
<service android:name="SMSService"/>
<receiver android:name="com.google.android.gcm.GCMBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="org.eehouse.android.xw4" />
</intent-filter>
</receiver>
<service android:name=".GCMIntentService" />
</application>
</manifest>

View file

@ -49,16 +49,28 @@
<!-- extension targets. Uncomment the ones where you want to do custom work
in between standard targets -->
<property name="INITIAL_CLIENT_VERS" value="3"/>
<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"/>
</exec>
<exec dir="." executable="../scripts/mkimages.sh"
failonerror="true" >
<arg value="--clean"/>
</exec>
</target>
<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="xw4dbg"/>
<arg value="--app-name"/>
<arg value="cWords-DBG"/>
<arg value="--dest-dir"/>
<arg value="./res"/>
<arg value="--dest-dir"/>
@ -67,15 +79,42 @@
<arg value="./jni"/>
<arg value="--dest-dir"/>
<arg value="./assets"/>
<arg value="--dest-dir"/>
<arg value="./libs"/>
<arg value="--dest-dir"/>
<arg value="./img_src"/>
</exec>
<exec dir="." executable="../scripts/ndkbuild.sh" >
<arg value="-j3"/>
</exec>
<exec dir=".." executable="./scripts/genvers.sh" output="ant_out.txt">
<arg value="XWords4-dbg"/>
<arg value="xw4dbg"/>
<exec dir="." executable="../scripts/ndksetup.sh" output="/dev/null">
<arg value="${build.target}"/>
</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 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
xwjni.c
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 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
bluetooth_active.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
btinviter_item.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
games_list_item_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"?>
<resources>
<string name="app_name">Crossw-dbg</string>
<string name="app_version">4.4-dbg beta 80</string>
</resources>

View file

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

View file

@ -22,7 +22,7 @@
to come from a domain that you own or have control over. -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.eehouse.android.xw4"
android:versionCode="68"
android:versionCode="76"
android:versionName="@string/app_version"
>
@ -67,7 +67,7 @@
android:name=".XWApp"
>
<activity android:name="GamesList"
<activity android:name="GamesListActivity"
android:label="@string/app_name"
android:launchMode="standard"
android:configChanges="keyboardHidden|orientation|screenSize"
@ -97,7 +97,7 @@
<activity android:name="SMSInviteActivity"
android:theme="@android:style/Theme.Dialog"
android:configChanges="keyboardHidden|orientation|screenSize"
android:screenOrientation="portrait"
android:screenOrientation="sensor"
/>
<activity android:name="GameConfig"
@ -120,9 +120,8 @@
android:configChanges="keyboardHidden"
/>
<activity android:name="LookupActivity"
<activity android:name="StudyListActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:theme="@android:style/Theme.Dialog"
/>
<receiver android:name="RelayReceiver">

View file

@ -49,12 +49,13 @@
<!-- extension targets. Uncomment the ones where you want to do custom work
in between standard targets -->
<property name="INITIAL_CLIENT_VERS" value="3"/>
<property name="INITIAL_CLIENT_VERS" value="4"/>
<target name="-pre-clean">
<exec dir="." executable="../scripts/ndksetup.sh" output="/dev/null">
<exec dir="." executable="../scripts/ndksetup.sh" output="/dev/null"
failonerror="true" >
<arg value="${build.target}"/>
</exec>
<exec dir="." executable="../scripts/ndkbuild.sh" output="/dev/null">
<exec dir="." executable="../scripts/ndkbuild.sh" failonerror="true" >
<arg value="clean"/>
</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)/dictnry.c \
$(COMMON_PATH)/dictiter.c \
$(COMMON_PATH)/dictmgr.c \
$(COMMON_PATH)/mscore.c \
$(COMMON_PATH)/vtabmgr.c \
$(COMMON_PATH)/strutils.c \
@ -89,5 +90,10 @@ LOCAL_LDLIBS := -L${SYSROOT}/usr/lib -llog -lz
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_PATH :=

View file

@ -42,6 +42,9 @@ typedef struct _AndDictionaryCtxt {
off_t bytesSize;
jbyte* bytes;
jbyteArray byteArray;
#ifdef DEBUG
uint32_t dbgid;
#endif
} AndDictionaryCtxt;
#define CHECK_PTR(p,c,e) \
@ -487,6 +490,7 @@ static void
and_dictionary_destroy( DictionaryCtxt* dict )
{
AndDictionaryCtxt* ctxt = (AndDictionaryCtxt*)dict;
XP_LOGF( "%s(dict=%p); code=%x", __func__, ctxt, ctxt->dbgid );
XP_U16 nSpecials = andCountSpecials( ctxt );
XP_U16 ii;
JNIEnv* env = ctxt->env;
@ -536,7 +540,10 @@ and_dictionary_destroy( DictionaryCtxt* dict )
jobject
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
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 ) );
anddict->env = env;
anddict->jniutil = jniutil;
#ifdef DEBUG
anddict->dbgid = rand();
#endif
dict_super_init( (DictionaryCtxt*)anddict );
MPASSIGN( anddict->super.mpool, mpool );
LOG_RETURNF( "%p", anddict );
return (DictionaryCtxt*)anddict;
}
void
makeDicts( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil,
makeDicts( MPFORMAL JNIEnv *env, DictMgrCtxt* dictMgr, JNIUtilCtxt* jniutil,
DictionaryCtxt** dictp, PlayerDicts* dicts,
jobjectArray jnames, jobjectArray jdicts, jobjectArray jpaths,
jstring jlang )
@ -576,7 +588,7 @@ makeDicts( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil,
NULL : (*env)->GetObjectArrayElement( env, jpaths, ii );
if ( NULL != jdict || NULL != jpath ) {
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 );
XP_ASSERT( !!dict );
deleteLocalRefs( env, jdict, jname, DELETE_NO_REF );
@ -593,74 +605,80 @@ makeDicts( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil,
}
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 )
{
jbyte* bytes = NULL;
jbyteArray byteArray = NULL;
off_t bytesSize = 0;
if ( NULL == jpath ) {
bytesSize = (*env)->GetArrayLength( env, jbytes );
byteArray = (*env)->NewGlobalRef( env, jbytes );
bytes = (*env)->GetByteArrayElements( env, byteArray, NULL );
} else {
const char* path = (*env)->GetStringUTFChars( env, jpath, NULL );
const char* name = (*env)->GetStringUTFChars( env, jname, NULL );
/* remember: dmgr_get calls dict_ref() */
AndDictionaryCtxt* anddict = (AndDictionaryCtxt*)dmgr_get( dictMgr, name );
struct stat statbuf;
if ( 0 == stat( path, &statbuf ) && 0 < statbuf.st_size ) {
int fd = open( path, O_RDONLY );
if ( fd >= 0 ) {
void* ptr = mmap( NULL, statbuf.st_size, PROT_READ,
MAP_PRIVATE, fd, 0 );
close( fd );
if ( MAP_FAILED != ptr ) {
bytes = ptr;
bytesSize = statbuf.st_size;
if ( NULL == anddict ) {
if ( NULL == jpath ) {
bytesSize = (*env)->GetArrayLength( env, jbytes );
byteArray = (*env)->NewGlobalRef( env, jbytes );
bytes = (*env)->GetByteArrayElements( env, byteArray, NULL );
} else {
const char* path = (*env)->GetStringUTFChars( env, jpath, NULL );
struct stat statbuf;
if ( 0 == stat( path, &statbuf ) && 0 < statbuf.st_size ) {
int fd = open( path, O_RDONLY );
if ( fd >= 0 ) {
void* ptr = mmap( NULL, statbuf.st_size, PROT_READ,
MAP_PRIVATE, fd, 0 );
close( fd );
if ( MAP_FAILED != ptr ) {
bytes = ptr;
bytesSize = statbuf.st_size;
}
}
}
(*env)->ReleaseStringUTFChars( env, jpath, path );
}
(*env)->ReleaseStringUTFChars( env, jpath, path );
}
AndDictionaryCtxt* anddict = NULL;
if ( NULL != bytes ) {
anddict = (AndDictionaryCtxt*)
and_dictionary_make_empty( MPPARM(mpool) env, jniutil );
anddict->bytes = bytes;
anddict->byteArray = byteArray;
anddict->bytesSize = bytesSize;
if ( NULL != bytes ) {
anddict = (AndDictionaryCtxt*)
and_dictionary_make_empty( MPPARM(mpool) env, jniutil );
anddict->bytes = bytes;
anddict->byteArray = byteArray;
anddict->bytesSize = bytesSize;
anddict->super.destructor = and_dictionary_destroy;
anddict->super.destructor = and_dictionary_destroy;
/* copy the name */
anddict->super.name = getStringCopy( MPPARM(mpool) env, jname );
anddict->super.langName = getStringCopy( MPPARM(mpool) env, jlangname );
/* copy the name */
anddict->super.name = copyString( mpool, name );
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_Bool parses = parseDict( anddict, (XP_U8*)anddict->bytes,
bytesSize, &numEdges );
if ( !parses || (check && !checkSanity( &anddict->super,
numEdges ) ) ) {
and_dictionary_destroy( (DictionaryCtxt*)anddict );
anddict = NULL;
XP_U32 numEdges;
XP_Bool parses = parseDict( anddict, (XP_U8*)anddict->bytes,
bytesSize, &numEdges );
if ( !parses || (check && !checkSanity( &anddict->super,
numEdges ) ) ) {
and_dictionary_destroy( (DictionaryCtxt*)anddict );
anddict = NULL;
}
}
dmgr_put( dictMgr, name, &anddict->super );
dict_ref( &anddict->super );
}
return (DictionaryCtxt*)anddict;
(*env)->ReleaseStringUTFChars( env, jname, name );
return &anddict->super;
} /* makeDict */
void
destroyDicts( PlayerDicts* dicts )
#ifdef DEBUG
uint32_t
andDictID( const DictionaryCtxt* dict )
{
int ii;
DictionaryCtxt** ctxts;
for ( ctxts = dicts->dicts, ii = 0;
ii < VSIZE(dicts->dicts);
++ii, ++ctxts ) {
if ( NULL != *ctxts ) {
dict_destroy( *ctxts );
}
}
const AndDictionaryCtxt* ctxt = (AndDictionaryCtxt*)dict;
return ctxt->dbgid;
}
#endif

View file

@ -22,6 +22,7 @@
#define _ANDDICT_H_
#include "dictnry.h"
#include "dictmgr.h"
#include "comtypes.h"
#include "jniutlswrapper.h"
@ -29,11 +30,11 @@ void
dict_splitFaces( DictionaryCtxt* dict, const XP_U8* bytes,
XP_U16 nBytes, XP_U16 nFaces );
DictionaryCtxt* makeDict( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil,
jstring jname, jbyteArray bytes, jstring path,
jstring jlang, jboolean check );
DictionaryCtxt* makeDict( MPFORMAL JNIEnv *env, DictMgrCtxt* dictMgr,
JNIUtilCtxt* jniutil, jstring jname, jbyteArray bytes,
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,
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 );
# ifdef DEBUG
uint32_t andDictID(const DictionaryCtxt* dict);
# endif
#endif

View file

@ -20,6 +20,7 @@
#include "drawwrapper.h"
#include "andutils.h"
#include "anddict.h"
#include "paths.h"
enum {
@ -517,6 +518,7 @@ static void
and_draw_dictChanged( DrawCtx* dctx, XP_S16 playerNum,
const DictionaryCtxt* dict )
{
XP_LOGF( "%s(dict=%p); code=%x", __func__, dict, andDictID(dict) );
AndDraw* draw = (AndDraw*)dctx;
if ( NULL != draw->jdraw ) {
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_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 );
}
}

View file

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

View file

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

View file

@ -30,6 +30,7 @@
#include "strutils.h"
#include "dictnry.h"
#include "dictiter.h"
#include "dictmgr.h"
#include "utilwrapper.h"
#include "drawwrapper.h"
@ -39,6 +40,45 @@
#include "jniutlswrapper.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[] = {
ARR_MEMBER( CurGameInfo, nPlayers )
,ARR_MEMBER( CurGameInfo, gameSeconds )
@ -316,18 +356,36 @@ Java_org_eehouse_android_xw4_jni_XwJNI_comms_1getUUID
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
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1getInfo
( JNIEnv* env, jclass C, jbyteArray jDictBytes, jstring jname, jstring jpath,
jobject jniu, jboolean check, jobject jinfo )
( JNIEnv* env, jclass C, jint jniGlobalPtr, jbyteArray jDictBytes,
jstring jname, jstring jpath, jobject jniu, jboolean check, jobject jinfo )
{
jboolean result = false;
#ifdef MEM_DEBUG
MemPoolCtx* mpool = mpool_make();
#endif
JNIUtilCtxt* jniutil = makeJNIUtil( MPPARM(mpool) &env, jniu );
DictionaryCtxt* dict = makeDict( MPPARM(mpool) env, jniutil, jname,
jDictBytes, jpath, NULL, check );
JNIGlobalState* state = (JNIGlobalState*)jniGlobalPtr;
JNIUtilCtxt* jniutil = makeJNIUtil( MPPARM(state->mpool) &env, jniu );
DictionaryCtxt* dict = makeDict( MPPARM(state->mpool) env, state->dictMgr,
jniutil, jname, jDictBytes, jpath, NULL, check );
if ( NULL != dict ) {
if ( NULL != jinfo ) {
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 ) );
setString( env, jinfo, "md5Sum", dict_getMd5Sum( dict ) );
}
dict_destroy( dict );
dict_unref( dict );
result = true;
}
destroyJNIUtil( &jniutil );
#ifdef MEM_DEBUG
mpool_destroy( mpool );
#endif
return result;
}
@ -380,6 +435,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_dict_1getTileValue
typedef struct _JNIState {
XWGame game;
JNIEnv* env;
JNIGlobalState* globalJNI;
AndGlobals globals;
XP_U16 curSaveCount;
XP_U16 lastSavedSize;
@ -422,22 +478,24 @@ typedef struct _JNIState {
JNIEXPORT jint JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_initJNI
( JNIEnv* env, jclass C )
( JNIEnv* env, jclass C, int jniGlobalPtr )
{
struct timeval tv;
gettimeofday( &tv, NULL );
srandom( tv.tv_sec );
/* Why am I doing this twice? */
/* struct timeval tv; */
/* gettimeofday( &tv, NULL ); */
/* srandom( tv.tv_sec ); */
#ifdef MEM_DEBUG
MemPoolCtx* mpool = mpool_make();
#endif
JNIState* state = (JNIState*)XP_CALLOC( mpool, sizeof(*state) );
state->globalJNI = (JNIGlobalState*)jniGlobalPtr;
AndGlobals* globals = &state->globals;
globals->state = (struct JNIState*)state;
MPASSIGN( state->mpool, mpool );
globals->vtMgr = make_vtablemgr(MPPARM_NOCOMMA(mpool));
XP_U32 secs = getCurSeconds( env );
XP_LOGF( "initing srand with %ld", secs );
XP_LOGF( "initing srand with %d", secs );
srandom( secs );
return (jint) state;
@ -471,8 +529,10 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeNewGame
DictionaryCtxt* dict;
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
if ( !dict ) {
XP_LOGF( "falling back to stubbed dict" );
@ -480,7 +540,9 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeNewGame
}
#endif
model_setDictionary( state->game.model, dict );
dict_unref( dict ); /* game owns it now */
model_setPlayerDicts( state->game.model, &dicts );
dict_unref_all( &dicts );
XWJNI_END();
} /* makeNewGame */
@ -526,8 +588,9 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeFromStream
globals->util = makeUtil( MPPARM(mpool) &state->env,
jutil, globals->gi, globals );
globals->jniutil = makeJNIUtil( MPPARM(mpool) &state->env, jniu );
makeDicts( MPPARM(mpool) env, globals->jniutil, &dict, &dicts, jdictNames,
jdicts, jpaths, jlang );
makeDicts( MPPARM(state->globalJNI->mpool) env, state->globalJNI->dictMgr,
globals->jniutil, &dict, &dicts, jdictNames, jdicts, jpaths,
jlang );
if ( !!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->xportProcs );
stream_destroy( stream );
dict_unref( dict ); /* game owns it now */
dict_unref_all( &dicts );
if ( result ) {
XP_ASSERT( 0 != globals->gi->gameID );
@ -552,10 +617,6 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeFromStream
} else {
destroyDraw( &globals->dctx );
destroyXportProcs( &globals->xportProcs );
destroyDicts( &dicts );
if ( NULL != dict ) {
dict_destroy( dict );
}
destroyUtil( &globals->util );
destroyJNIUtil( &globals->jniutil );
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, "missingPlayers",
server_getMissingPlayers( state->game.server ) );
setInt( env, jsummary, "nPacketsPending",
comms_countPendingPackets( state->game.comms ) );
if ( COMMS_CONN_RELAY == addr.conType ) {
XP_UCHAR buf[128];
XP_U16 len = VSIZE(buf);
@ -1405,6 +1468,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1getGi
static const SetInfo gsi_ints[] = {
ARR_MEMBER( GameStateInfo, visTileCount ),
ARR_MEMBER( GameStateInfo, nPendingMessages ),
ARR_MEMBER( GameStateInfo, trayVisState ),
};
static const SetInfo gsi_bools[] = {
@ -1452,9 +1516,12 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1changeDict
jbyteArray jDictBytes, jstring jpath )
{
XWJNI_START_GLOBALS();
DictionaryCtxt* dict = makeDict( MPPARM(mpool) env, globals->jniutil,
jname, jDictBytes, jpath, NULL, false );
DictionaryCtxt* dict = makeDict( MPPARM(state->globalJNI->mpool) env,
state->globalJNI->dictMgr,
globals->jniutil, jname, jDictBytes,
jpath, NULL, false );
game_changeDict( MPPARM(mpool) &state->game, globals->gi, dict );
dict_unref( dict );
setJGI( env, jgi, globals->gi );
XWJNI_END();
return XP_FALSE; /* no need to redraw */
@ -1510,6 +1577,25 @@ Java_org_eehouse_android_xw4_jni_XwJNI_comms_1isConnected
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
Java_org_eehouse_android_xw4_jni_XwJNI_server_1endGame
( JNIEnv* env, jclass C, jint gamePtr )
@ -1554,33 +1640,29 @@ typedef struct _DictIterData {
JNIEXPORT jint JNICALL
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 )
{
jint closure = 0;
#ifdef MEM_DEBUG
MemPoolCtx* mpool = mpool_make();
#endif
DictIterData* data = XP_CALLOC( mpool, sizeof(*data) );
JNIGlobalState* state = (JNIGlobalState*)jniGlobalPtr;
DictIterData* data = XP_CALLOC( state->mpool, sizeof(*data) );
data->env = env;
JNIUtilCtxt* jniutil = makeJNIUtil( MPPARM(mpool) &data->env, jniu );
DictionaryCtxt* dict = makeDict( MPPARM(mpool) env, jniutil, jname,
jDictBytes, jpath, NULL, false );
JNIUtilCtxt* jniutil = makeJNIUtil( MPPARM(state->mpool) &data->env, jniu );
DictionaryCtxt* dict = makeDict( MPPARM(state->mpool) env, state->dictMgr,
jniutil, jname, jDictBytes, jpath, NULL,
false );
if ( !!dict ) {
data->vtMgr = make_vtablemgr( MPPARM_NOCOMMA(mpool) );
data->vtMgr = make_vtablemgr( MPPARM_NOCOMMA(state->mpool) );
data->jniutil = jniutil;
data->dict = dict;
data->depth = 2;
#ifdef MEM_DEBUG
data->mpool = mpool;
data->mpool = state->mpool;
#endif
closure = (int)data;
} else {
destroyJNIUtil( &jniutil );
XP_FREE( mpool, data );
#ifdef MEM_DEBUG
mpool_destroy( mpool );
#endif
XP_FREE( state->mpool, data );
}
return closure;
}
@ -1651,14 +1733,11 @@ Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1destroy
#ifdef MEM_DEBUG
MemPoolCtx* mpool = data->mpool;
#endif
dict_destroy( data->dict );
dict_unref( data->dict );
destroyJNIUtil( &data->jniutil );
freeIndices( data );
vtmgr_destroy( MPPARM(mpool) data->vtMgr );
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
# Project target.
target=Google Inc.:Google APIs:14
target=android-14

View file

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

View file

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

View file

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

View file

@ -13,6 +13,12 @@
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"
android:layout_width="wrap_content"
android:layout_height="wrap_content"

View file

@ -1,10 +1,11 @@
<?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"
>
<org.eehouse.android.xw4.LookupAlert
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView android:id="@+id/summary"
android:layout_height="wrap_content"
@ -19,9 +20,13 @@
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"
android:layout_width="fill_parent"
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>
</item>
<item android:id="@+id/games_menu_study"
android:title="@string/gamel_menu_study"
/>
<item android:id="@+id/gamel_menu_checkmoves"
android:title="@string/gamel_menu_checkmoves"
/>
@ -94,4 +98,7 @@
android:alphabeticShortcut="A"
/>
<item android:id="@+id/board_menu_game_netstats"
android:title="@string/board_menu_game_netstats" />
</menu>

View file

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

View file

@ -16,11 +16,19 @@
android:icon="@drawable/prefs__gen"
android:showAsAction="ifRoom"
/>
<item android:id="@+id/games_menu_rateme"
android:title="@string/menu_rateme"
/>
<item android:id="@+id/games_menu_dicts"
android:title="@string/gamel_menu_dicts"
android:icon="@drawable/dict__gen"
android:showAsAction="ifRoom"
/>
<item android:id="@+id/games_menu_study"
android:title="@string/gamel_menu_study"
/>
<item android:id="@+id/games_menu_email"
android:title="@string/board_menu_file_email"
android:icon="@drawable/email__gen"
@ -30,6 +38,9 @@
android:title="@string/board_menu_file_about"
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"
android:title="@string/gamel_menu_checkmoves"
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>
</head>
<body>
<b>Crosswords 4.4 beta 76 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>
<b>Crosswords 4.4 beta 83 release</b>
<h3>New with this release</h3>
<ul>
<li>Add thumbnails of board to main screen</li>
<li>Add ability to invite via NFC</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>
<li>Display board in upside-down portrait orientation too (where OS version allows)</li>
<li>Bug fix (obscure): don't mangle unicode model names</li>
</ul>
<h3>Next up</h3>
<ul>
<li>Much better support for localization</li>
<li>Look, again, at play via Bluetooth now that HTC phones aren't quite so common</li>
<li>Fix SMS play for KitKat</li>
<li>Use Actionbar and select/act pattern on more screens</li>
<li>Offer "Rematch" when game's over</li>
</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_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_lost"> Torn perdut.</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_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_lost"> Tah ztracen.</string>
<string name="badwords_title">Neplatné slovo[a]</string>

View file

@ -157,12 +157,6 @@
list_item_rename) -->
<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:
@ -605,7 +599,7 @@
phonies_disallow is the current setting and a "phony" is
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>
<!-- 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_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="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_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_lost"> Ťah stratený.</string>
<string name="badwords_title">Neplatné slovo[á]</string>

View file

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

View file

@ -59,6 +59,7 @@
<string name="key_enable_sms">key_enable_sms</string>
<string name="key_keep_screenon">key_keep_screenon</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_default_loc">key_default_loc</string>
@ -107,6 +108,7 @@
<string name="key_na_browse">key_na_browse</string>
<string name="key_na_browseall">key_na_browseall</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_dup_invite">key_enable_dup_invite</string>
<string name="key_download_path">key_download_path</string>
@ -122,6 +124,7 @@
<string name="invite_mime">application/x-xwordsinvite</string>
<string name="game_summary_field_rowid">rowid</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="dict_url">http://eehouse.org/and_wordlists</string>
@ -141,6 +144,8 @@
only)</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="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="relay_port">Relay game port</string>

View file

@ -159,8 +159,8 @@
<!-- Text of confirmation dialog posted when list_item_reset menu
is selected -->
<string name="confirm_reset">Are you sure you want to reset the
selected game[s]? (Resetting erases all moves and any connection
<string name="confirm_resetf">Are you sure you want to reset the %d
selected game[s]?\n\n(Resetting erases all moves and any connection
information.)</string>
<!--
@ -601,7 +601,7 @@
phonies_disallow is the current setting and a "phony" is
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>
<!-- 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
because users should not have to do do this EVER. -->
<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 name="about_versf">Crosswords for Android, Version %1$s,
rev %2$s.</string>
rev %2$s, built on %3$s.</string>
<!-- 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
License.</string>
@ -1788,10 +1789,13 @@
<!-- New strings that need to be documented and found a home
above. -->
<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_lookup_studyf">Look up/study %s</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>
<!-- -->
@ -2119,14 +2123,10 @@
<string name="group_cur_games">My games</string>
<string name="group_new_games">New games</string>
<string name="group_confirm_del">Are you sure you want to delete
the selected group?</string>
<string name="groups_confirm_del">Are you sure you want to delete
the selected groups?</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="groups_confirm_delf">Are you sure you want to delete
the %d selected group[s]?</string>
<string name="groups_confirm_del_gamesf">\n\n(%d game[s] will
also be deleted.)</string>
<string name="rename_group_label">Change the name of this group to:</string>
<string name="game_name_group_title">Name group</string>
@ -2167,13 +2167,12 @@
<string name="sel_groupsf">Groups: %d</string>
<string name="summary_thumbsize">Thumbnail size</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="dropped_dupe">Invitation received but ignored: it
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="enable_nfc">NFC is turned off on this device. You
@ -2197,4 +2196,39 @@
browsers for viewing the wordlists downloads page, DO NOT choose
Firefox. Some versions have a bug that can cause the wordlists to
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>

View file

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

View file

@ -246,6 +246,11 @@
android:summary="@string/summary_sort_tiles"
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"
android:title="@string/ringer_zoom"
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
* 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 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
* 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
* rights reserved.
@ -481,7 +481,7 @@ public class BTService extends XWService {
host.getAddress() );
for ( long rowid : rowids ) {
if ( BoardActivity.feedMessage( gameID, buffer, addr ) ) {
if ( BoardDelegate.feedMessage( gameID, buffer, addr ) ) {
// do nothing
} else if ( haveGame &&
GameUtils.feedMessage( BTService.this, rowid,
@ -968,7 +968,7 @@ public class BTService extends XWService {
private void postNotification( int gameID, int title, String body,
long rowid )
{
Intent intent = GamesList.makeGameIDIntent( this, gameID );
Intent intent = GamesListActivity.makeGameIDIntent( this, gameID );
Utils.postNotification( this, intent, R.string.new_btmove_title,
body, (int)rowid );
}
@ -1018,12 +1018,6 @@ public class BTService extends XWService {
}
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
* 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.JNIThread;
import org.eehouse.android.xw4.jni.XwJNI;
import org.eehouse.android.xw4.jni.XwJNI.DictWrapper;
import junit.framework.Assert;
@ -84,7 +85,7 @@ public class BoardCanvas extends Canvas implements DrawCtx {
private Drawable m_downArrow;
private int m_trayOwner = -1;
private int m_pendingScore;
private int m_dictPtr = 0;
private DictWrapper m_dict;
protected String[] m_dictChars;
private boolean m_hasSmallScreen;
private int m_backgroundUsed = 0x00000000;
@ -142,6 +143,7 @@ public class BoardCanvas extends Canvas implements DrawCtx {
m_activity = activity;
m_bitmap = bitmap;
m_jniThread = jniThread;
m_dict = new DictWrapper();
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 ) {
if ( 0 == dictPtr ) {
int curPtr = m_dict.getDictPtr();
if ( curPtr != newPtr ) {
if ( 0 == newPtr ) {
m_fontDims = null;
m_dictChars = null;
} else if ( m_dictPtr == 0 ||
!XwJNI.dict_tilesAreSame( m_dictPtr, dictPtr ) ) {
} else if ( 0 == curPtr
|| !XwJNI.dict_tilesAreSame( curPtr, newPtr ) ) {
m_fontDims = null;
m_dictChars = null;
m_activity.runOnUiThread( new Runnable() {
public void run() {
if ( null != m_jniThread ) {
m_dictChars = XwJNI.dict_getChars( dictPtr );
m_dictChars = XwJNI.dict_getChars( newPtr );
// draw again
m_jniThread.handle( JNIThread.JNICmd
.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
* rights reserved.
@ -20,6 +20,7 @@
package org.eehouse.android.xw4;
import android.app.Activity;
import android.view.View;
import android.graphics.Canvas;
import android.graphics.Paint;
@ -51,13 +52,14 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
private Context m_context;
private int m_defaultFontHt;
private int m_mediumFontHt;
private Runnable m_invalidator;
private int m_jniGamePtr;
private CurGameInfo m_gi;
private int m_layoutWidth;
private int m_layoutHeight;
private BoardCanvas m_canvas; // owns the bitmap
private JNIThread m_jniThread;
private XWActivity m_parent;
private Activity m_parent;
private boolean m_measuredFromDims = false;
private BoardDims m_dims;
private CommsAddrRec.CommsConnType m_connType =
@ -76,6 +78,11 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
final float scale = getResources().getDisplayMetrics().density;
m_defaultFontHt = (int)(MIN_FONT_DIPS * scale + 0.5f);
m_mediumFontHt = m_defaultFontHt * 3 / 2;
m_invalidator = new Runnable() {
public void run() {
invalidate();
}
};
}
@Override
@ -203,6 +210,8 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
// nothing to do
} else if ( null == m_gi ) {
// nothing to do either
} else if ( null == m_jniThread ) {
// nothing to do either
} else if ( null == m_dims ) {
// m_canvas = null;
// need to synchronize??
@ -249,7 +258,7 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
} // layoutBoardOnce
// BoardHandler interface implementation
public void startHandling( XWActivity parent, JNIThread thread,
public void startHandling( Activity parent, JNIThread thread,
int gamePtr, CurGameInfo gi,
CommsAddrRec.CommsConnType connType )
{
@ -291,11 +300,7 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
}
// Force update now that we have bits to copy
m_parent.runOnUiThread( new Runnable() {
public void run() {
invalidate();
}
});
m_parent.runOnUiThread( m_invalidator );
}
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
* reserved.
@ -33,9 +33,9 @@ import android.view.MenuItem;
import android.view.MenuInflater;
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
public void onCreate( Bundle savedInstanceState )
@ -45,33 +45,7 @@ public class ChatActivity extends XWActivity implements View.OnClickListener {
setContentView( R.layout.chat );
m_rowid = getIntent().getLongExtra( GameUtils.INTENT_KEY_ROWID, -1 );
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();
m_dlgt = new ChatDelegate( this, savedInstanceState );
}
}
@ -86,33 +60,7 @@ public class ChatActivity extends XWActivity implements View.OnClickListener {
@Override
public boolean onOptionsItemSelected( MenuItem item )
{
boolean handled = R.id.chat_menu_clear == item.getItemId();
if ( handled ) {
DBUtils.clearChatHistory( this, m_rowid );
LinearLayout layout =
(LinearLayout)findViewById( R.id.chat_history );
layout.removeAllViews();
} else {
handled = super.onOptionsItemSelected( item );
}
return handled;
return m_dlgt.onOptionsItemSelected( item )
|| super.onOptionsItemSelected( item );
}
@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
* rights reserved.
@ -387,32 +387,18 @@ public class CommsTransport implements TransportProcs,
m_relayAddr = new CommsAddrRec( addr );
}
switch ( addr.conType ) {
case COMMS_CONN_RELAY:
if ( XWApp.UDP_ENABLED ) {
nSent = RelayService.sendPacket( m_context, m_rowid, buf );
} else {
if ( NetStateCache.netAvail( m_context ) ) {
putOut( buf ); // add to queue
if ( null == m_thread ) {
m_thread = new CommsThread();
m_thread.start();
}
nSent = buf.length;
if ( !XWApp.UDP_ENABLED
&& CommsConnType.COMMS_CONN_RELAY == addr.conType ) {
if ( NetStateCache.netAvail( m_context ) ) {
putOut( buf ); // add to queue
if ( null == m_thread ) {
m_thread = new CommsThread();
m_thread.start();
}
nSent = buf.length;
}
break;
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;
} else {
nSent = sendForAddr( m_context, addr, m_rowid, gameID, buf );
}
// Keep this while debugging why the resend_all that gets
@ -468,6 +454,30 @@ public class CommsTransport implements TransportProcs,
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
* 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
@ -477,5 +487,4 @@ public class CommsTransport implements TransportProcs,
* perhaps catch NPEs here just to be safe. But then do what?
* 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
* rights reserved.
@ -237,9 +237,9 @@ public class ConnStatusHandler {
updateStatusImpl( context, cbacks, connType, success, false );
}
public static void updateStatusImpl( Context context, ConnStatusCBacks cbacks,
CommsConnType connType, boolean success,
boolean isIn )
private static void updateStatusImpl( Context context, ConnStatusCBacks cbacks,
CommsConnType connType, boolean success,
boolean isIn )
{
if ( null == cbacks ) {
cbacks = s_cbacks;

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
* 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_DICTINFO = "dictinfo";
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 int DB_VERSION = 18;
private static final int DB_VERSION = 20;
public static final String GAME_NAME = "GAME_NAME";
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 LASTMOVE = "LASTMOVE";
public static final String GROUPID = "GROUPID";
public static final String NPACKETSPENDING = "NPACKETSPENDING";
public static final String DICTNAME = "DICTNAME";
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 EXPANDED = "EXPANDED";
public static final String WORD = "WORD";
public static final String LANGUAGE = "LANGUAGE";
private Context m_context;
private static final String[][] s_summaryColsAndTypes = {
@ -120,6 +125,7 @@ public class DBHelper extends SQLiteOpenHelper {
,{ CONTRACTED, "INTEGER DEFAULT 0" }
,{ CREATE_TIME, "INTEGER" }
,{ LASTPLAY_TIME,"INTEGER" }
,{ NPACKETSPENDING,"INTEGER" }
,{ SNAPSHOT, "BLOB" }
,{ THUMBNAIL, "BLOB" }
};
@ -153,6 +159,12 @@ public class DBHelper extends SQLiteOpenHelper {
,{ EXPANDED, "INTEGER(1)" }
};
private static final String[][] s_studySchema = {
{ WORD, "TEXT" }
,{ LANGUAGE, "INTEGER(1)" }
,{ "UNIQUE", "(" + WORD + ", " + LANGUAGE + ")" }
};
public DBHelper( Context context )
{
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_DICTBROWSE, s_dictBrowseColsAndTypes );
forceRowidHigh( db, TABLE_NAME_SUM );
createGroupsTable( db );
createGroupsTable( db, false );
createStudyTable( db );
}
@Override
@ -181,6 +194,7 @@ public class DBHelper extends SQLiteOpenHelper {
{
DbgUtils.logf( "onUpgrade: old: %d; new: %d", oldVersion, newVersion );
boolean madeSumTable = false;
switch( oldVersion ) {
case 5:
createTable( db, TABLE_NAME_OBITS, s_obitsColsAndTypes );
@ -206,16 +220,26 @@ public class DBHelper extends SQLiteOpenHelper {
addSumColumn( db, LASTMOVE );
case 14:
addSumColumn( db, GROUPID );
createGroupsTable( db );
createGroupsTable( db, true );
case 15:
moveToCurGames( db );
case 16:
addSumColumn( db, VISID );
setColumnsEqual( db, TABLE_NAME_SUM, VISID, "rowid" );
makeAutoincrement( db, TABLE_NAME_SUM, s_summaryColsAndTypes );
madeSumTable = true;
case 17:
addSumColumn( db, THUMBNAIL );
// nothing yet
if ( !madeSumTable ) {
// THUMBNAIL also added by makeAutoincrement above
addSumColumn( db, THUMBNAIL );
}
case 18:
createStudyTable( db );
case 19:
if ( !madeSumTable ) {
// NPACKETSPENDING also added by makeAutoincrement above
addSumColumn( db, NPACKETSPENDING );
}
break;
default:
db.execSQL( "DROP TABLE " + TABLE_NAME_SUM + ";" );
@ -256,28 +280,40 @@ public class DBHelper extends SQLiteOpenHelper {
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 );
// Create an empty group name
ContentValues values = new ContentValues();
values.put( GROUPNAME, m_context.getString(R.string.group_cur_games) );
values.put( EXPANDED, 1 );
long curGroup = db.insert( TABLE_NAME_GROUPS, null, values );
if ( isUpgrade ) {
values.put( GROUPNAME, m_context.getString(R.string.group_cur_games) );
values.put( EXPANDED, 1 );
long curGroup = db.insert( TABLE_NAME_GROUPS, null, values );
// place all existing games in the initial unnamed group
values = new ContentValues();
values.put( GROUPID, curGroup );
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 );
// place all existing games in the initial unnamed group
values = new ContentValues();
values.put( GROUPID, curGroup );
db.update( DBHelper.TABLE_NAME_SUM, values, null, null );
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'
private void moveToCurGames( SQLiteDatabase db )
{
@ -362,4 +398,16 @@ public class DBHelper extends SQLiteOpenHelper {
query = String.format( "DELETE FROM %s", name );
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
* rights reserved.
@ -50,6 +50,7 @@ import java.util.StringTokenizer;
import junit.framework.Assert;
import org.eehouse.android.xw4.jni.*;
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
import org.eehouse.android.xw4.DictUtils.DictLoc;
@ -135,7 +136,7 @@ public class DBUtils {
DBHelper.DICTLANG, DBHelper.GAMEID,
DBHelper.SCORES, DBHelper.HASMSGS,
DBHelper.LASTPLAY_TIME, DBHelper.REMOTEDEVS,
DBHelper.LASTMOVE
DBHelper.LASTMOVE, DBHelper.NPACKETSPENDING
};
String selection = String.format( ROW_ID_FMT, lock.getRowid() );
@ -202,13 +203,18 @@ public class DBUtils {
summary.scores = scores;
int col = cursor.getColumnIndex( DBHelper.CONTYPE );
if ( col >= 0 ) {
if ( 0 <= col ) {
tmp = cursor.getInt( col );
summary.conType = CommsAddrRec.CommsConnType.values()[tmp];
col = cursor.getColumnIndex( DBHelper.SEED );
if ( col >= 0 ) {
if ( 0 < col ) {
summary.seed = cursor.getInt( col );
}
col = cursor.getColumnIndex( DBHelper.NPACKETSPENDING );
if ( 0 <= col ) {
summary.nPacketsPending = cursor.getInt( col );
}
switch ( summary.conType ) {
case COMMS_CONN_RELAY:
col = cursor.getColumnIndex( DBHelper.ROOMNAME );
@ -295,6 +301,7 @@ public class DBUtils {
if ( null != summary.conType ) {
values.put( DBHelper.CONTYPE, summary.conType.ordinal() );
values.put( DBHelper.SEED, summary.seed );
values.put( DBHelper.NPACKETSPENDING, summary.nPacketsPending );
switch( summary.conType ) {
case COMMS_CONN_RELAY:
values.put( DBHelper.ROOMNAME, summary.roomName );
@ -493,6 +500,30 @@ public class DBUtils {
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 )
{
long[] result = null;
@ -610,19 +641,20 @@ public class DBUtils {
NetLaunchInfo nli )
{
Date result = null;
String[] columns = { DBHelper.CREATE_TIME };
String selection =
String.format( "%s='%s' AND %s='%s' AND %s=%d AND %s=%d",
DBHelper.ROOMNAME, nli.room,
DBHelper.INVITEID, nli.inviteID,
DBHelper.DICTLANG, nli.lang,
DBHelper.NUM_PLAYERS, nli.nPlayersT );
String[] selectionArgs = new String[] {
DBHelper.ROOMNAME, nli.room,
DBHelper.INVITEID, nli.inviteID,
DBHelper.DICTLANG, String.format( "%d", nli.lang ),
DBHelper.NUM_PLAYERS, String.format( "%d", nli.nPlayersT )
};
initDB( context );
synchronized( s_dbHelper ) {
SQLiteDatabase db = s_dbHelper.getReadableDatabase();
Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns,
selection, null, null, null,
DBHelper.CREATE_TIME + " DESC" ); // order by
Cursor cursor = db.rawQuery( "SELECT " + DBHelper.CREATE_TIME +
" FROM " + DBHelper.TABLE_NAME_SUM +
" WHERE ?=? AND ?=? AND ?=? AND ?=?",
selectionArgs );
if ( cursor.moveToNext() ) {
int indx = cursor.getColumnIndex( DBHelper.CREATE_TIME );
result = new Date( cursor.getLong( indx ) );
@ -932,14 +964,16 @@ public class DBUtils {
// Groups stuff
public static class GameGroupInfo {
public String m_name;
public int m_count;
public boolean m_expanded;
public long m_lastMoveTime;
public boolean m_hasTurn;
public boolean m_turnLocal;
public GameGroupInfo( String name, boolean expanded ) {
public GameGroupInfo( String name, int count, boolean expanded ) {
m_name = name; m_expanded = expanded;
m_lastMoveTime = 0;
m_count = count;
}
}
@ -978,44 +1012,58 @@ public class DBUtils {
return thumb;
}
// Return map of string (group name) to info about all games in
// that group.
public static HashMap<Long,GameGroupInfo> getGroups( Context context )
private static HashMap<Long, Integer> getGameCounts( SQLiteDatabase db )
{
return getGroups( context, 0 );
HashMap<Long, Integer> result = new HashMap<Long, Integer>();
String query = "SELECT %s, count(%s) as cnt FROM %s GROUP BY %s";
query = String.format( query, DBHelper.GROUPID, DBHelper.GROUPID,
DBHelper.TABLE_NAME_SUM, DBHelper.GROUPID );
Cursor cursor = db.rawQuery( query, null );
int rowIndex = cursor.getColumnIndex( DBHelper.GROUPID );
int cntIndex = cursor.getColumnIndex( "cnt" );
while ( cursor.moveToNext() ) {
long row = cursor.getLong(rowIndex);
int count = cursor.getInt(cntIndex);
result.put( row, count );
}
cursor.close();
return result;
}
private static HashMap<Long,GameGroupInfo> getGroups( Context context,
int nRows )
// Map of groups rowid (= summaries.groupid) to group info record
protected static HashMap<Long,GameGroupInfo> getGroups( Context context )
{
if ( null == s_groupsCache ) {
HashMap<Long,GameGroupInfo> result =
new HashMap<Long,GameGroupInfo>();
String[] columns = { ROW_ID, DBHelper.GROUPNAME,
DBHelper.EXPANDED };
String limit = 0 == nRows ? null : String.format( "%d", nRows );
// Select all groups. For each group get the number of games in
// that group. There should be a way to do that with one query
// but I can't figure it out.
String query = "SELECT rowid, groupname as groups_groupname, "
+ " groups.expanded as groups_expanded FROM groups";
DbgUtils.logf( "query: %s", query );
initDB( context );
synchronized( s_dbHelper ) {
SQLiteDatabase db = s_dbHelper.getReadableDatabase();
Cursor cursor = db.query( DBHelper.TABLE_NAME_GROUPS, columns,
null, // selection
null, // args
null, // groupBy
null, // having
null, //orderby
limit
);
int idIndex = cursor.getColumnIndex( ROW_ID );
int nameIndex = cursor.getColumnIndex( DBHelper.GROUPNAME );
int expandedIndex = cursor.getColumnIndex( DBHelper.EXPANDED );
HashMap<Long, Integer> map = getGameCounts( db );
Cursor cursor = db.rawQuery( query, null );
int idIndex = cursor.getColumnIndex( "rowid" );
int nameIndex = cursor.getColumnIndex( "groups_groupname" );
int expandedIndex = cursor.getColumnIndex( "groups_expanded" );
while ( cursor.moveToNext() ) {
String name = cursor.getString( nameIndex );
long id = cursor.getLong( idIndex );
String name = cursor.getString( nameIndex );
Assert.assertNotNull( name );
boolean expanded = 0 != cursor.getInt( expandedIndex );
result.put( id, new GameGroupInfo( name, expanded ) );
int count = map.containsKey( id ) ? map.get( id ) : 0;
result.put( id, new GameGroupInfo( name, count, expanded ) );
}
cursor.close();
@ -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 )
{
long[] result = null;
@ -1170,7 +1240,7 @@ public class DBUtils {
public static long getAnyGroup( Context context )
{
long result = GROUPID_UNSPEC;
HashMap<Long,GameGroupInfo> groups = getGroups( context, 1 );
HashMap<Long,GameGroupInfo> groups = getGroups( context );
Iterator<Long> iter = groups.keySet().iterator();
if ( iter.hasNext() ) {
result = iter.next();
@ -1564,6 +1634,96 @@ public class DBUtils {
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 )
{
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
* 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
* rights reserved.
@ -42,6 +42,7 @@ import java.util.Arrays;
import junit.framework.Assert;
import org.eehouse.android.xw4.DlgDelegate.Action;
import org.eehouse.android.xw4.jni.JNIUtilsImpl;
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 int MIN_LEN = 2;
private static final int FINISH_ACTION = 1;
private int m_dictClosure = 0;
private int m_lang;
@ -194,7 +194,7 @@ public class DictBrowseActivity extends XWListActivity
// search/minmax stuff.
String msg = Utils.format( this, R.string.alert_empty_dictf,
name );
showOKOnlyDialogThen( msg, FINISH_ACTION );
showOKOnlyDialogThen( msg, Action.FINISH_ACTION );
} else {
figureMinMax( m_browseState.m_counts );
if ( newState ) {
@ -288,11 +288,14 @@ public class DictBrowseActivity extends XWListActivity
int position, long id )
{
TextView text = (TextView)view;
int newval = Integer.parseInt( text.getText().toString() );
if ( parent == m_minSpinner ) {
setMinMax( newval, m_browseState.m_maxShown );
} else if ( parent == m_maxSpinner ) {
setMinMax( m_browseState.m_minShown, newval );
// null text seems to have generated at least one google play report
if ( null != text ) {
int newval = Integer.parseInt( text.getText().toString() );
if ( parent == m_minSpinner ) {
setMinMax( newval, m_browseState.m_maxShown );
} else if ( parent == m_maxSpinner ) {
setMinMax( m_browseState.m_minShown, newval );
}
}
}
@ -304,9 +307,9 @@ public class DictBrowseActivity extends XWListActivity
// DlgDelegate.DlgClickNotify interface
//////////////////////////////////////////////////
@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();
}

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
* 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
* 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 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
* 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
* rights reserved.
@ -20,10 +20,10 @@
package org.eehouse.android.xw4;
import android.text.TextUtils;
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;
@ -34,16 +34,17 @@ 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.AdapterView;
import android.widget.PopupMenu;
import android.widget.TextView;
@ -54,315 +55,32 @@ 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 DictsActivity extends XWExpandableListActivity
implements View.OnClickListener, AdapterView.OnItemLongClickListener,
SelectableItem, MountEventReceiver.SDCardNotifiee,
DlgDelegate.DlgClickNotify,
DictImportActivity.DownloadFinishedListener {
public class DictsActivity extends ExpandableListActivity {
private static interface SafePopup {
public void doPopup( Context context, View button, String curDict );
}
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
// settle for a hash on the side.
private static HashMap<MenuItem, DictAndLoc> s_itemData;
private String[] m_langs;
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;
}
}
private DictsDelegate m_dlgt;
@Override
protected Dialog onCreateDialog( int id )
{
OnClickListener lstnr, lstnr2;
Dialog dialog;
String format;
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;
Dialog dialog = super.onCreateDialog( id );
if ( null == dialog ) {
dialog = m_dlgt.createDialog( id );
}
if ( doRemove && null != dialog ) {
Utils.setRemoveOnDismiss( this, dialog, id );
}
return dialog;
} // onCreateDialog
@ -370,402 +88,53 @@ public class DictsActivity extends XWExpandableListActivity
protected void onPrepareDialog( int id, Dialog dialog )
{
super.onPrepareDialog( 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 );
}
m_dlgt.prepareDialog( id, dialog );
}
@Override
protected void onCreate( Bundle savedInstanceState )
{
super.onCreate( 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();
m_dlgt = new DictsDelegate( this, savedInstanceState );
} // onCreate
@Override
protected void onResume()
{
super.onResume();
MountEventReceiver.register( this );
mkListAdapter();
expandGroups();
m_dlgt.onResume();
}
@Override
protected void onStop() {
MountEventReceiver.unregister( this );
m_dlgt.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
public void onBackPressed() {
if ( 0 == m_selDicts.size() ) {
if ( !m_dlgt.onBackPressed() ) {
super.onBackPressed();
} else {
clearSelections();
}
}
@Override
public boolean onCreateOptionsMenu( Menu menu )
{
MenuInflater inflater = getMenuInflater();
inflater.inflate( R.menu.dicts_menu, menu );
return true;
return m_dlgt.onCreateOptionsMenu( menu );
}
@Override
public 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 super.onPrepareOptionsMenu( menu );
return m_dlgt.onPrepareOptionsMenu( menu )
|| super.onPrepareOptionsMenu( menu );
}
public 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:
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;
return m_dlgt.onOptionsItemSelected( item )
|| super.onOptionsItemSelected( item );
}
private static Intent mkDownloadIntent( Context context, String dict_url )
@ -787,13 +156,13 @@ public class DictsActivity extends XWExpandableListActivity
String name )
{
Intent intent = new Intent( activity, DictsActivity.class );
intent.putExtra( DICT_DOLAUNCH, true );
intent.putExtra( DictsDelegate.DICT_DOLAUNCH, true );
if ( lang > 0 ) {
intent.putExtra( DICT_LANG_EXTRA, lang );
intent.putExtra( DictsDelegate.DICT_LANG_EXTRA, lang );
}
if ( null != name ) {
Assert.assertTrue( lang != 0 );
intent.putExtra( DICT_NAME_EXTRA, name );
intent.putExtra( DictsDelegate.DICT_NAME_EXTRA, name );
}
activity.startActivity( intent );
@ -809,53 +178,6 @@ public class DictsActivity extends XWExpandableListActivity
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 {
public void doPopup( final Context context, View button,
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
* reserved.
@ -40,7 +40,7 @@ public class DispatchNotify extends Activity {
Uri data = getIntent().getData();
if ( null != data ) { // relay invite redirected URL case
GamesList.openGame( this, data );
GamesListActivity.openGame( this, data );
}
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 reserved.
@ -39,25 +39,79 @@ import junit.framework.Assert;
public class DlgDelegate {
public static final int DIALOG_ABOUT = 1;
public static final int DIALOG_OKONLY = 2;
public static final int DIALOG_NOTAGAIN = 3;
public static final int CONFIRM_THEN = 4;
public static final int INVITE_CHOICES_THEN = 5;
public static final int DLG_DICTGONE = 6;
public static final int DIALOG_LAST = DLG_DICTGONE;
public static enum Action {
SKIP_CALLBACK,
// GameListDelegate
RESET_GAMES,
SYNC_MENU,
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 EMAIL_BTN = AlertDialog.BUTTON_NEGATIVE;
public static final int NFC_BTN = AlertDialog.BUTTON_NEUTRAL;
public static final int DISMISS_BUTTON = 0;
public static final int SKIP_CALLBACK = -1;
private static final String IDS = "IDS";
private static final String STATE_KEYF = "STATE_%d";
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;
@ -66,7 +120,7 @@ public class DlgDelegate {
private ProgressDialog m_progress;
private Handler m_handler;
private HashMap<Integer, DlgState> m_dlgStates;
private HashMap<DlgID, DlgState> m_dlgStates;
public DlgDelegate( Activity activity, DlgClickNotify callback,
Bundle bundle )
@ -74,7 +128,7 @@ public class DlgDelegate {
m_activity = activity;
m_clickCallback = callback;
m_handler = new Handler();
m_dlgStates = new HashMap<Integer,DlgState>();
m_dlgStates = new HashMap<DlgID,DlgState>();
if ( null != bundle ) {
int[] ids = bundle.getIntArray( IDS );
@ -93,34 +147,44 @@ public class DlgDelegate {
Iterator<DlgState> iter = m_dlgStates.values().iterator();
while ( iter.hasNext() ) {
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 );
ids[indx++] = state.m_id;
ids[indx++] = id;
}
}
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;
DlgState state = findForID( id );
switch( id ) {
DlgID dlgID = DlgID.values()[id];
DlgState state = findForID( dlgID );
switch( dlgID ) {
case LOOKUP:
dialog = createLookupDialog();
break;
case DIALOG_ABOUT:
dialog = createAboutDialog();
break;
case DIALOG_OKONLY:
dialog = createOKDialog( state, id );
dialog = createOKDialog( state, dlgID );
break;
case DIALOG_NOTAGAIN:
dialog = createNotAgainDialog( state, id );
dialog = createNotAgainDialog( state, dlgID );
break;
case CONFIRM_THEN:
dialog = createConfirmThenDialog( state, id );
dialog = createConfirmThenDialog( state, dlgID );
break;
case INVITE_CHOICES_THEN:
dialog = createInviteChoicesDialog( state, id );
dialog = createInviteChoicesDialog( state, dlgID );
break;
case DLG_DICTGONE:
dialog = createDictGoneDialog();
@ -131,52 +195,52 @@ public class DlgDelegate {
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 );
DlgState state = new DlgState( DIALOG_OKONLY, msg, callbackID );
DlgState state = new DlgState( DlgID.DIALOG_OKONLY, msg, action );
addState( state );
m_activity.showDialog( DIALOG_OKONLY );
m_activity.showDialog( DlgID.DIALOG_OKONLY.ordinal() );
}
public void showOKOnlyDialog( int msgID )
{
showOKOnlyDialog( m_activity.getString( msgID ), SKIP_CALLBACK );
showOKOnlyDialog( m_activity.getString( msgID ), Action.SKIP_CALLBACK );
}
public void showDictGoneFinish()
{
m_activity.showDialog( DLG_DICTGONE );
m_activity.showDialog( DlgID.DLG_DICTGONE.ordinal() );
}
public void showAboutDialog()
{
m_activity.showDialog( DIALOG_ABOUT );
m_activity.showDialog( DlgID.DIALOG_ABOUT.ordinal() );
}
public void showNotAgainDlgThen( int msgID, int prefsKey,
final int callbackID,
final Action action,
final Object[] params )
{
showNotAgainDlgThen( m_activity.getString( msgID ), prefsKey,
callbackID, params );
action, params );
}
public void showNotAgainDlgThen( String msg, int prefsKey,
final int callbackID,
final Action action,
final Object[] params )
{
if ( XWPrefs.getPrefsBoolean( m_activity, prefsKey, false ) ) {
// If it's set, do the action without bothering with the
// dialog
if ( SKIP_CALLBACK != callbackID ) {
if ( Action.SKIP_CALLBACK != action ) {
post( new Runnable() {
public void run() {
m_clickCallback
.dlgButtonClicked( callbackID,
.dlgButtonClicked( action,
AlertDialog.BUTTON_POSITIVE,
params );
}
@ -184,59 +248,72 @@ public class DlgDelegate {
}
} else {
DlgState state =
new DlgState( DIALOG_NOTAGAIN, msg, callbackID, prefsKey,
new DlgState( DlgID.DIALOG_NOTAGAIN, msg, action, prefsKey,
params );
addState( state );
m_activity.showDialog( DIALOG_NOTAGAIN );
m_activity.showDialog( DlgID.DIALOG_NOTAGAIN.ordinal() );
}
}
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 )
{
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 )
{
DlgState state = new DlgState( CONFIRM_THEN, msg, posButton,
callbackID, 0, params );
addState( state );
m_activity.showDialog( CONFIRM_THEN );
showConfirmThen( m_activity.getString( msg ), posButton, action,
params );
}
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 )
|| NFCUtils.nfcAvail( m_activity )[0] ) {
DlgState state = new DlgState( INVITE_CHOICES_THEN, callbackID );
DlgState state = new DlgState( DlgID.INVITE_CHOICES_THEN, action );
addState( state );
m_activity.showDialog( INVITE_CHOICES_THEN );
m_activity.showDialog( DlgID.INVITE_CHOICES_THEN.ordinal() );
} else {
post( new Runnable() {
public void run() {
m_clickCallback.dlgButtonClicked( callbackID, EMAIL_BTN,
m_clickCallback.dlgButtonClicked( action, EMAIL_BTN,
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 );
intent.putExtra( LookupActivity.WORDS, words );
intent.putExtra( LookupActivity.LANG, lang );
m_activity.startActivity( intent );
Bundle params = LookupAlert.makeParams( words, lang, noStudyOption );
addState( new DlgState( DlgID.LOOKUP, new Object[]{params} ) );
m_activity.showDialog( DlgID.LOOKUP.ordinal() );
}
public void startProgress( int id )
@ -315,7 +390,7 @@ public class DlgDelegate {
post( new Runnable() {
public void run() {
if ( asDlg ) {
showOKOnlyDialog( fmsg, SKIP_CALLBACK );
showOKOnlyDialog( fmsg, Action.SKIP_CALLBACK );
} else {
DbgUtils.showf( m_activity, fmsg );
}
@ -330,7 +405,8 @@ public class DlgDelegate {
TextView vers = (TextView)view.findViewById( R.id.version_string );
vers.setText( String.format( m_activity.getString(R.string.about_versf),
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 );
String str = m_activity.getString( R.string.xlator );
@ -344,7 +420,7 @@ public class DlgDelegate {
.setIcon( R.drawable.icon48x48 )
.setTitle( R.string.app_name )
.setView( view )
.setPositiveButton( R.string.changes_button,
.setNegativeButton( R.string.changes_button,
new OnClickListener() {
@Override
public void onClick( DialogInterface dlg,
@ -353,22 +429,30 @@ public class DlgDelegate {
FirstRunDialog.show( m_activity );
}
} )
.setPositiveButton( R.string.button_ok, null )
.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 )
.setTitle( R.string.info_title )
.setMessage( state.m_msg )
.setPositiveButton( R.string.button_ok, null )
.create();
dialog = setCallbackDismissListener( dialog, state, id );
dialog = setCallbackDismissListener( dialog, state, dlgID );
return dialog;
}
private Dialog createNotAgainDialog( final DlgState state, int id )
private Dialog createNotAgainDialog( final DlgState state, DlgID dlgID )
{
OnClickListener lstnr_p = mkCallbackClickListener( state );
@ -377,9 +461,9 @@ public class DlgDelegate {
public void onClick( DialogInterface dlg, int item ) {
XWPrefs.setPrefsBoolean( m_activity, state.m_prefsKey,
true );
if ( SKIP_CALLBACK != state.m_cbckID ) {
if ( Action.SKIP_CALLBACK != state.m_action ) {
m_clickCallback.
dlgButtonClicked( state.m_cbckID,
dlgButtonClicked( state.m_action,
AlertDialog.BUTTON_POSITIVE,
state.m_params );
}
@ -393,10 +477,10 @@ public class DlgDelegate {
.setNegativeButton( R.string.button_notagain, lstnr_n )
.create();
return setCallbackDismissListener( dialog, state, id );
return setCallbackDismissListener( dialog, state, dlgID );
} // createNotAgainDialog
private Dialog createConfirmThenDialog( DlgState state, int id )
private Dialog createConfirmThenDialog( DlgState state, DlgID dlgID )
{
OnClickListener lstnr = mkCallbackClickListener( state );
@ -407,10 +491,10 @@ public class DlgDelegate {
.setNegativeButton( R.string.button_cancel, lstnr )
.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 );
@ -437,7 +521,7 @@ public class DlgDelegate {
builder.setNeutralButton( R.string.button_nfc, lstnr );
}
return setCallbackDismissListener( builder.create(), state, id );
return setCallbackDismissListener( builder.create(), state, dlgID );
}
private Dialog createDictGoneDialog()
@ -462,8 +546,8 @@ public class DlgDelegate {
OnClickListener cbkOnClickLstnr;
cbkOnClickLstnr = new OnClickListener() {
public void onClick( DialogInterface dlg, int button ) {
if ( SKIP_CALLBACK != state.m_cbckID ) {
m_clickCallback.dlgButtonClicked( state.m_cbckID,
if ( Action.SKIP_CALLBACK != state.m_action ) {
m_clickCallback.dlgButtonClicked( state.m_action,
button,
state.m_params );
}
@ -474,14 +558,15 @@ public class DlgDelegate {
private Dialog setCallbackDismissListener( final Dialog dialog,
final DlgState state,
final int id )
DlgID dlgID )
{
final int id = dlgID.ordinal();
DialogInterface.OnDismissListener cbkOnDismissLstnr
= new DialogInterface.OnDismissListener() {
public void onDismiss( DialogInterface di ) {
dropState( state );
if ( SKIP_CALLBACK != state.m_cbckID ) {
m_clickCallback.dlgButtonClicked( state.m_cbckID,
if ( Action.SKIP_CALLBACK != state.m_action ) {
m_clickCallback.dlgButtonClicked( state.m_action,
DISMISS_BUTTON,
state.m_params );
}
@ -493,9 +578,9 @@ public class DlgDelegate {
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 );
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
* rights reserved.
@ -20,54 +20,61 @@
package org.eehouse.android.xw4;
import org.eehouse.android.xw4.DlgDelegate.Action;
import android.os.Parcelable;
import android.os.Parcel;
public class DlgState implements Parcelable {
public int m_id;
public DlgID m_id;
public String m_msg;
public int m_posButton;
public int m_cbckID = 0;
public Action m_action = null;
public int m_prefsKey;
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 )
{
this( id, msg, R.string.button_ok, cbckID, prefsKey );
this( dlgID, msg, R.string.button_ok, action, prefsKey );
m_params = params;
}
public DlgState( int id, String msg, int posButton,
int cbckID, int prefsKey )
public DlgState( DlgID dlgID, String msg, int posButton,
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,
int cbckID, int prefsKey, Object[] params )
public DlgState( DlgID dlgID, String msg, int posButton,
Action action, int prefsKey, Object[] params )
{
m_id = id;
m_id = dlgID;
m_msg = msg;
m_posButton = posButton;
m_cbckID = cbckID;
m_action = action;
m_prefsKey = prefsKey;
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() {
@ -75,9 +82,9 @@ public class DlgState implements Parcelable {
}
public void writeToParcel( Parcel out, int flags ) {
out.writeInt( m_id );
out.writeInt( m_id.ordinal() );
out.writeInt( m_posButton );
out.writeInt( m_cbckID );
out.writeInt( null == m_action ? -1 : m_action.ordinal() );
out.writeInt( m_prefsKey );
out.writeString( m_msg );
}
@ -85,12 +92,13 @@ public class DlgState implements Parcelable {
public static final Parcelable.Creator<DlgState> CREATOR
= new Parcelable.Creator<DlgState>() {
public DlgState createFromParcel(Parcel in) {
int id = in.readInt();
DlgID id = DlgID.values()[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();
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) {

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