mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-08 05:24:39 +01:00
Merge remote-tracking branch 'origin/android_branch' into android_translate
This commit is contained in:
commit
5c14ad3f22
199 changed files with 6510 additions and 1769 deletions
|
@ -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.xw4dbg"
|
||||
android:versionCode="91"
|
||||
android:versionCode="95"
|
||||
android:versionName="@string/app_version"
|
||||
>
|
||||
|
||||
|
@ -70,6 +70,7 @@
|
|||
<application android:icon="@drawable/icon48x48"
|
||||
android:label="@string/app_name"
|
||||
android:name=".XWApp"
|
||||
android:debuggable="true"
|
||||
>
|
||||
|
||||
<activity android:name="GamesListActivity"
|
||||
|
@ -106,6 +107,11 @@
|
|||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
android:screenOrientation="sensor"
|
||||
/>
|
||||
<activity android:name="RelayInviteActivity"
|
||||
android:label="@string/relay_invite_title"
|
||||
android:theme="@android:style/Theme.Dialog"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
/>
|
||||
|
||||
<activity android:name="GameConfigActivity"
|
||||
android:screenOrientation="sensor"
|
||||
|
|
|
@ -2,3 +2,4 @@ BasEnglish2to8.xwd
|
|||
CollegeEng_2to8.xwd
|
||||
Top5000.xwd
|
||||
changes.html
|
||||
gitvers.txt
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name="XWords4" default="release">
|
||||
|
||||
<!-- eeh: allow ant files to refer e.g. to ${env.HOME} -->
|
||||
<property environment="env" />
|
||||
|
||||
<!-- The local.properties file is created and updated by the 'android' tool.
|
||||
It contains the path to the SDK. It should *NOT* be checked into
|
||||
Version Control Systems. -->
|
||||
|
@ -52,7 +55,7 @@
|
|||
<!-- extension targets. Uncomment the ones where you want to do custom work
|
||||
in between standard targets -->
|
||||
|
||||
<property name="INITIAL_CLIENT_VERS" value="4"/>
|
||||
<property name="INITIAL_CLIENT_VERS" value="8"/>
|
||||
<property name="VARIANT_NAME" value="xw4dbg"/>
|
||||
<property name="APP_NAME" value="CrossDbg"/>
|
||||
|
||||
|
|
Binary file not shown.
BIN
xwords4/android/XWords4-dbg/libs/crittercism_v5_2_0_sdkonly.jar
Normal file
BIN
xwords4/android/XWords4-dbg/libs/crittercism_v5_2_0_sdkonly.jar
Normal file
Binary file not shown.
|
@ -41,5 +41,6 @@ conn_types_display.xml
|
|||
expander_header.xml
|
||||
msg_label_and_edit.xml
|
||||
not_again_view.xml
|
||||
relayinviter.xml
|
||||
remote_dict_details.xml
|
||||
toolbar.xml
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
board_menu.xml
|
||||
chat_menu.xml
|
||||
dicts_item_menu.xml
|
||||
games_list_item_menu.xml
|
||||
games_list_menu.xml
|
||||
dicts_menu.xml
|
||||
studylist.xml
|
||||
loc_menu.xml
|
||||
empty.xml
|
||||
loc_item_menu.xml
|
||||
games_list_group_menu.xml
|
||||
games_list_game_menu.xml
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<resources>
|
||||
<string name="app_version">4.4-dbg beta 80</string>
|
||||
</resources>
|
|
@ -1 +1,2 @@
|
|||
/strings.xml
|
||||
strings.xml
|
||||
|
|
1
xwords4/android/XWords4-dbg/res_src/values-ca/.gitignore
vendored
Normal file
1
xwords4/android/XWords4-dbg/res_src/values-ca/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
strings.xml
|
|
@ -1 +1,2 @@
|
|||
/strings.xml
|
||||
strings.xml
|
||||
|
|
1
xwords4/android/XWords4-dbg/res_src/values-cs/.gitignore
vendored
Normal file
1
xwords4/android/XWords4-dbg/res_src/values-cs/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
strings.xml
|
1
xwords4/android/XWords4-dbg/res_src/values-fr/.gitignore
vendored
Normal file
1
xwords4/android/XWords4-dbg/res_src/values-fr/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
strings.xml
|
1
xwords4/android/XWords4-dbg/res_src/values-nl/.gitignore
vendored
Normal file
1
xwords4/android/XWords4-dbg/res_src/values-nl/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
strings.xml
|
1
xwords4/android/XWords4-dbg/res_src/values-pt/.gitignore
vendored
Normal file
1
xwords4/android/XWords4-dbg/res_src/values-pt/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
strings.xml
|
1
xwords4/android/XWords4-dbg/res_src/values-sk/.gitignore
vendored
Normal file
1
xwords4/android/XWords4-dbg/res_src/values-sk/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
strings.xml
|
|
@ -1,4 +1,3 @@
|
|||
#CrashTrack.java#
|
||||
/DlgID.java
|
||||
/LookupAlert.java
|
||||
ABUtils.java
|
||||
|
@ -113,11 +112,16 @@ GroupStateListener.java
|
|||
ListGroup.java
|
||||
ConnViaViewLayout.java
|
||||
Delegator.java
|
||||
DevID.java
|
||||
HeaderWithExpander.java
|
||||
LangListPreference.java
|
||||
ListDelegator.java
|
||||
NagTurnReceiver.java
|
||||
NotAgainView.java
|
||||
OnBootReceiver.java
|
||||
RelayInviteActivity.java
|
||||
RelayInviteDelegate.java
|
||||
XWConnAddrPreference.java
|
||||
XWDevIDPreference.java
|
||||
XWExpListAdapter.java
|
||||
RequestCode.java
|
||||
|
|
16
xwords4/android/XWords4/.gitignore
vendored
16
xwords4/android/XWords4/.gitignore
vendored
|
@ -1,9 +1,19 @@
|
|||
*.apk
|
||||
.DS_Store
|
||||
.gradle
|
||||
/.idea/libraries
|
||||
/.idea/workspace.xml
|
||||
/build
|
||||
/captures
|
||||
/libs-debug
|
||||
/libs-release
|
||||
/local.properties
|
||||
/obj-debug
|
||||
/obj-release
|
||||
ant_out.txt
|
||||
local.properties
|
||||
bin
|
||||
gen
|
||||
libs
|
||||
proguard.cfg
|
||||
local.properties
|
||||
obj
|
||||
proguard.cfg
|
||||
res/drawable*/*gen.png
|
||||
|
|
1
xwords4/android/XWords4/.idea/.name
Normal file
1
xwords4/android/XWords4/.idea/.name
Normal file
|
@ -0,0 +1 @@
|
|||
XWords4
|
231
xwords4/android/XWords4/.idea/codeStyleSettings.xml
Normal file
231
xwords4/android/XWords4/.idea/codeStyleSettings.xml
Normal file
|
@ -0,0 +1,231 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectCodeStyleSettingsManager">
|
||||
<option name="PER_PROJECT_SETTINGS">
|
||||
<value>
|
||||
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
|
||||
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
|
||||
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
|
||||
<value />
|
||||
</option>
|
||||
<option name="IMPORT_LAYOUT_TABLE">
|
||||
<value>
|
||||
<package name="android" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="com" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="junit" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="net" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="org" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="java" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="javax" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="" withSubpackages="true" static="true" />
|
||||
<emptyLine />
|
||||
</value>
|
||||
</option>
|
||||
<option name="RIGHT_MARGIN" value="100" />
|
||||
<AndroidXmlCodeStyleSettings>
|
||||
<option name="USE_CUSTOM_SETTINGS" value="true" />
|
||||
</AndroidXmlCodeStyleSettings>
|
||||
<Objective-C-extensions>
|
||||
<option name="GENERATE_INSTANCE_VARIABLES_FOR_PROPERTIES" value="ASK" />
|
||||
<option name="RELEASE_STYLE" value="IVAR" />
|
||||
<option name="TYPE_QUALIFIERS_PLACEMENT" value="BEFORE" />
|
||||
<file>
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
|
||||
</file>
|
||||
<class>
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
|
||||
</class>
|
||||
<extensions>
|
||||
<pair source="cpp" header="h" />
|
||||
<pair source="c" header="h" />
|
||||
</extensions>
|
||||
</Objective-C-extensions>
|
||||
<XML>
|
||||
<option name="XML_KEEP_LINE_BREAKS" value="false" />
|
||||
<option name="XML_ALIGN_ATTRIBUTES" value="false" />
|
||||
<option name="XML_SPACE_INSIDE_EMPTY_TAG" value="true" />
|
||||
</XML>
|
||||
<codeStyleSettings language="XML">
|
||||
<option name="FORCE_REARRANGE_MODE" value="1" />
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
</indentOptions>
|
||||
<arrangement>
|
||||
<rules>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:android</NAME>
|
||||
<XML_NAMESPACE />
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:.*</NAME>
|
||||
<XML_NAMESPACE />
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:id</NAME>
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:name</NAME>
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>name</NAME>
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>style</NAME>
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:layout_width</NAME>
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:layout_height</NAME>
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:layout_.*</NAME>
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:width</NAME>
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:height</NAME>
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
</rules>
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
</value>
|
||||
</option>
|
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default (1)" />
|
||||
</component>
|
||||
</project>
|
22
xwords4/android/XWords4/.idea/compiler.xml
Normal file
22
xwords4/android/XWords4/.idea/compiler.xml
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<resourceExtensions />
|
||||
<wildcardResourcePatterns>
|
||||
<entry name="!?*.java" />
|
||||
<entry name="!?*.form" />
|
||||
<entry name="!?*.class" />
|
||||
<entry name="!?*.groovy" />
|
||||
<entry name="!?*.scala" />
|
||||
<entry name="!?*.flex" />
|
||||
<entry name="!?*.kt" />
|
||||
<entry name="!?*.clj" />
|
||||
<entry name="!?*.aj" />
|
||||
</wildcardResourcePatterns>
|
||||
<annotationProcessing>
|
||||
<profile default="true" name="Default" enabled="false">
|
||||
<processorPath useClasspath="true" />
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
</component>
|
||||
</project>
|
|
@ -0,0 +1,3 @@
|
|||
<component name="CopyrightManager">
|
||||
<settings default="" />
|
||||
</component>
|
18
xwords4/android/XWords4/.idea/gradle.xml
Normal file
18
xwords4/android/XWords4/.idea/gradle.xml
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="gradleJvm" value="1.7" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/app" />
|
||||
</set>
|
||||
</option>
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
62
xwords4/android/XWords4/.idea/misc.xml
Normal file
62
xwords4/android/XWords4/.idea/misc.xml
Normal file
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="EntryPointsManager">
|
||||
<entry_points version="2.0" />
|
||||
</component>
|
||||
<component name="NullableNotNullManager">
|
||||
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
|
||||
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
|
||||
<option name="myNullables">
|
||||
<value>
|
||||
<list size="4">
|
||||
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
|
||||
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
|
||||
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
|
||||
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
<option name="myNotNulls">
|
||||
<value>
|
||||
<list size="4">
|
||||
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
|
||||
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
|
||||
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
|
||||
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
|
||||
<OptionsSetting value="true" id="Add" />
|
||||
<OptionsSetting value="true" id="Remove" />
|
||||
<OptionsSetting value="true" id="Checkout" />
|
||||
<OptionsSetting value="true" id="Update" />
|
||||
<OptionsSetting value="true" id="Status" />
|
||||
<OptionsSetting value="true" id="Edit" />
|
||||
<ConfirmationsSetting value="0" id="Add" />
|
||||
<ConfirmationsSetting value="0" id="Remove" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.7" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
<option name="id" value="Android" />
|
||||
</component>
|
||||
<component name="masterDetails">
|
||||
<states>
|
||||
<state key="ProjectJDKs.UI">
|
||||
<settings>
|
||||
<last-edited>1.7</last-edited>
|
||||
<splitter-proportions>
|
||||
<option name="proportions">
|
||||
<list>
|
||||
<option value="0.2" />
|
||||
</list>
|
||||
</option>
|
||||
</splitter-proportions>
|
||||
</settings>
|
||||
</state>
|
||||
</states>
|
||||
</component>
|
||||
</project>
|
9
xwords4/android/XWords4/.idea/modules.xml
Normal file
9
xwords4/android/XWords4/.idea/modules.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/XWords4.iml" filepath="$PROJECT_DIR$/XWords4.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
12
xwords4/android/XWords4/.idea/runConfigurations.xml
Normal file
12
xwords4/android/XWords4/.idea/runConfigurations.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RunConfigurationProducerService">
|
||||
<option name="ignoredProducers">
|
||||
<set>
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
|
||||
</set>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
6
xwords4/android/XWords4/.idea/vcs.xml
Normal file
6
xwords4/android/XWords4/.idea/vcs.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/../../.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
|
@ -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="91"
|
||||
android:versionCode="95"
|
||||
android:versionName="@string/app_version"
|
||||
>
|
||||
|
||||
|
@ -37,6 +37,7 @@
|
|||
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" />
|
||||
|
@ -102,6 +103,11 @@
|
|||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
android:screenOrientation="sensor"
|
||||
/>
|
||||
<activity android:name="RelayInviteActivity"
|
||||
android:label="@string/relay_invite_title"
|
||||
android:theme="@android:style/Theme.Dialog"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
/>
|
||||
|
||||
<activity android:name="GameConfigActivity"
|
||||
android:screenOrientation="sensor"
|
||||
|
|
19
xwords4/android/XWords4/XWords4.iml
Normal file
19
xwords4/android/XWords4/XWords4.iml
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module external.linked.project.id="XWords4" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="java-gradle" name="Java-Gradle">
|
||||
<configuration>
|
||||
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
|
||||
<option name="BUILDABLE" value="false" />
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_6" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
1
xwords4/android/XWords4/app/.gitignore
vendored
Normal file
1
xwords4/android/XWords4/app/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/build
|
93
xwords4/android/XWords4/app/app.iml
Normal file
93
xwords4/android/XWords4/app/app.iml
Normal file
|
@ -0,0 +1,93 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="XWords4" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="android-gradle" name="Android-Gradle">
|
||||
<configuration>
|
||||
<option name="GRADLE_PROJECT_PATH" value=":app" />
|
||||
</configuration>
|
||||
</facet>
|
||||
<facet type="android" name="Android">
|
||||
<configuration>
|
||||
<option name="SELECTED_BUILD_VARIANT" value="debug" />
|
||||
<option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
|
||||
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
|
||||
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
|
||||
<option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugAndroidTest" />
|
||||
<option name="COMPILE_JAVA_TEST_TASK_NAME" value="compileDebugAndroidTestSources" />
|
||||
<afterSyncTasks>
|
||||
<task>generateDebugAndroidTestSources</task>
|
||||
<task>generateDebugSources</task>
|
||||
</afterSyncTasks>
|
||||
<option name="ALLOW_USER_CONFIGURATION" value="false" />
|
||||
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
|
||||
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
|
||||
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
|
||||
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_6" inherit-compiler-output="false">
|
||||
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
|
||||
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/androidTest/debug" />
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes-proguard" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/debug" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/mockable-android-14.jar" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/proguard-rules" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/release" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/reports" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/test-results" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Android API 14 Platform" jdkType="Android SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" exported="" name="gcm" level="project" />
|
||||
</component>
|
||||
</module>
|
209
xwords4/android/XWords4/app/build.gradle
Normal file
209
xwords4/android/XWords4/app/build.gradle
Normal file
|
@ -0,0 +1,209 @@
|
|||
def VARIANT_NAME = 'xw4'
|
||||
def INITIAL_CLIENT_VERS = 6
|
||||
def CHAT_ENABLED = true
|
||||
def THUMBNAIL_ENABLED = true
|
||||
def LIBS_DEBUG = 'libs-debug'
|
||||
def LIBS_RELEASE = 'libs-release'
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
dependencies {
|
||||
compile files('../libs/gcm.jar')
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 22
|
||||
buildToolsVersion "22.0.1"
|
||||
defaultConfig {
|
||||
applicationId "org.eehouse.android.xw4"
|
||||
minSdkVersion 7
|
||||
targetSdkVersion 14
|
||||
}
|
||||
|
||||
// Rename all output artifacts to include version information
|
||||
applicationVariants.all { variant ->
|
||||
renameArtifact(variant)
|
||||
}
|
||||
|
||||
// flavorDimensions "variant", "abi"
|
||||
// productFlavors {
|
||||
// xw4 {
|
||||
// dimension "variant"
|
||||
// }
|
||||
// xw4dbg {
|
||||
// dimension "variant"
|
||||
// }
|
||||
// armeabiv7a {
|
||||
// dimension "abi"
|
||||
// }
|
||||
|
||||
// armeabi {
|
||||
// dimension "abi"
|
||||
// }
|
||||
|
||||
// x86 {
|
||||
// dimension "abi"
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
signingConfigs {
|
||||
release {
|
||||
storeFile file(System.getenv("HOME") + "/.keystore")
|
||||
keyAlias "mykey"
|
||||
|
||||
// These two lines make gradle believe that the signingConfigs
|
||||
// section is complete. Without them, tasks like installRelease
|
||||
// will not be available!
|
||||
storePassword "notReal"
|
||||
keyPassword "notReal"
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
signingConfig signingConfigs.release
|
||||
debuggable false
|
||||
minifyEnabled true
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
debug {
|
||||
debuggable true
|
||||
// This doesn't work on marshmallow: duplicate permission error
|
||||
// applicationIdSuffix ".debug"
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
// Use symlinks instead of setting non-conventional
|
||||
// directories here. AS doesn't respect what's set here: it'll
|
||||
// compile, but post-install app launch and source-level
|
||||
// debugging don't work.
|
||||
release {
|
||||
jniLibs.srcDir "../$LIBS_RELEASE"
|
||||
}
|
||||
debug {
|
||||
jniLibs.srcDir "../$LIBS_DEBUG"
|
||||
}
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
}
|
||||
|
||||
task genVers(type: Exec) {
|
||||
workingDir '../'
|
||||
commandLine '../scripts/genvers.sh', '--variant', VARIANT_NAME,
|
||||
'--client-vers', INITIAL_CLIENT_VERS, '--chat-enabled', CHAT_ENABLED,
|
||||
'--thumbnail-enabled', THUMBNAIL_ENABLED,
|
||||
'--vers-outfile', "assets/gitvers.txt"
|
||||
}
|
||||
|
||||
task mkImages(type: Exec) {
|
||||
workingDir '../'
|
||||
commandLine '../scripts/mkimages.sh'
|
||||
}
|
||||
|
||||
task copyStrings(type: Exec) {
|
||||
workingDir '../'
|
||||
commandLine '../scripts/copy-strings.py'
|
||||
}
|
||||
|
||||
task ndkSetup(type: Exec) {
|
||||
workingDir '../'
|
||||
commandLine "../scripts/ndksetup.sh"
|
||||
}
|
||||
|
||||
task genGcmid(type: Exec) {
|
||||
workingDir '../'
|
||||
commandLine '../scripts/gen_gcmid.sh',
|
||||
'-o', "src/org/eehouse/android/$VARIANT_NAME/GCMConsts.java",
|
||||
'-v', "$VARIANT_NAME"
|
||||
}
|
||||
|
||||
task myPreBuild(dependsOn: ['genVers', 'ndkSetup', 'mkImages', 'copyStrings', 'mkXml', 'genGcmid']) {
|
||||
}
|
||||
preBuild.dependsOn myPreBuild
|
||||
|
||||
task ndkBuildDebug(type: Exec) {
|
||||
workingDir '../'
|
||||
commandLine '../scripts/ndkbuild.sh', '-j3', "CHAT_ENABLED=$CHAT_ENABLED",
|
||||
"THUMBNAIL_ENABLED=$THUMBNAIL_ENABLED", 'BUILD_TARGET=debug',
|
||||
"INITIAL_CLIENT_VERS=$INITIAL_CLIENT_VERS", "VARIANT=$VARIANT_NAME",
|
||||
"NDK_LIBS_OUT=$LIBS_DEBUG", 'NDK_OUT=./obj-debug'
|
||||
}
|
||||
|
||||
task ndkBuildRelease(type: Exec) {
|
||||
workingDir '../'
|
||||
commandLine '../scripts/ndkbuild.sh', '-j3', "CHAT_ENABLED=$CHAT_ENABLED",
|
||||
"THUMBNAIL_ENABLED=$THUMBNAIL_ENABLED", 'BUILD_TARGET=release',
|
||||
"INITIAL_CLIENT_VERS=$INITIAL_CLIENT_VERS", "VARIANT=$VARIANT_NAME",
|
||||
"NDK_LIBS_OUT=$LIBS_RELEASE", 'NDK_OUT=./obj-release'
|
||||
}
|
||||
|
||||
task mkXml(type: Exec) {
|
||||
workingDir '../'
|
||||
commandLine '../scripts/mk_xml.py', '-o',
|
||||
"src/org/eehouse/android/$VARIANT_NAME/loc/LocIDsData.java",
|
||||
'-t', "debug", '-v', "$VARIANT_NAME"
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
compileReleaseNdk.dependsOn ndkBuildRelease
|
||||
compileDebugNdk.dependsOn ndkBuildDebug
|
||||
}
|
||||
|
||||
task askForPassword << {
|
||||
def password = System.getenv("ANDROID_KEY_PASS")
|
||||
if (null == password || 0 == password.length()) {
|
||||
if ( null != System.console() ) {
|
||||
password = new String(System.console()
|
||||
.readPassword("ANDROID_KEY_PASS not set; "
|
||||
+ "Keystore password: "))
|
||||
} else {
|
||||
password = null
|
||||
println( "ANDROID_KEY_PASS not set and no console; " )
|
||||
println( "sign it yerself later. (Or you might try" )
|
||||
println( " running gradlew with the --no-daemon flag)" )
|
||||
}
|
||||
}
|
||||
|
||||
if ( null != password ) {
|
||||
android.signingConfigs.release.storePassword = password
|
||||
android.signingConfigs.release.keyPassword = password
|
||||
}
|
||||
}
|
||||
|
||||
tasks.whenTaskAdded { theTask ->
|
||||
if (theTask.name.equals("packageRelease")) {
|
||||
theTask.dependsOn "askForPassword"
|
||||
}
|
||||
}
|
||||
|
||||
def getVersionName() {
|
||||
try {
|
||||
def stdout = new ByteArrayOutputStream()
|
||||
exec {
|
||||
commandLine 'git', 'describe', '--dirty'
|
||||
standardOutput = stdout
|
||||
}
|
||||
return stdout.toString().trim()
|
||||
}
|
||||
catch (ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
def renameArtifact(variant) {
|
||||
variant.outputs.each { output ->
|
||||
def name = String.format( "XWords4-%s-%s.apk", variant.name,
|
||||
getVersionName() )
|
||||
output.outputFile = new File( (String)output.outputFile.parent,
|
||||
(String)name )
|
||||
}
|
||||
}
|
34
xwords4/android/XWords4/app/proguard-rules.pro
vendored
Normal file
34
xwords4/android/XWords4/app/proguard-rules.pro
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in /home/eehouse/android/android-sdk-linux/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# 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 *;
|
||||
#}
|
||||
|
||||
# Keep everything. Useful maybe for confirming that proguard's causing
|
||||
# a problem?
|
||||
# -keep class ** { *; }
|
||||
|
||||
# Don't turn this on until it's clear that proguard isn't messing
|
||||
# anything else up. It'll make crash reports useless.
|
||||
|
||||
-dontobfuscate
|
||||
|
||||
# Uncomment this if obfuscation is enabled (by removing the line
|
||||
# above), and save the mapping.txt file or confirm it can be rebuilt
|
||||
# from a tag.
|
||||
# -keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# Prevents crash when jni code calls setInt on various jin.* classes
|
||||
-keep public class org.eehouse.android.xw4.jni.** { public *; }
|
1
xwords4/android/XWords4/app/src/main/AndroidManifest.xml
Symbolic link
1
xwords4/android/XWords4/app/src/main/AndroidManifest.xml
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../../AndroidManifest.xml
|
1
xwords4/android/XWords4/app/src/main/assets
Symbolic link
1
xwords4/android/XWords4/app/src/main/assets
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../../assets/
|
1
xwords4/android/XWords4/app/src/main/java
Symbolic link
1
xwords4/android/XWords4/app/src/main/java
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../../src/
|
1
xwords4/android/XWords4/app/src/main/res
Symbolic link
1
xwords4/android/XWords4/app/src/main/res
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../../res
|
1
xwords4/android/XWords4/assets/.gitignore
vendored
Normal file
1
xwords4/android/XWords4/assets/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/gitvers.txt
|
|
@ -13,10 +13,10 @@
|
|||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Crosswords 4.4 beta 98 release</h2>
|
||||
<h2>Crosswords 4.4 beta 101 release</h2>
|
||||
|
||||
<p>This release is mostly to get the new Dutch translation out
|
||||
there, and to catch up Catalan and French.</p>
|
||||
<p>This is the second of two releases that together fix stalling
|
||||
issues in network games.</p>
|
||||
|
||||
<div id="survey">
|
||||
<p>Please <a href="https://www.surveymonkey.com/s/GX3XLHR">take
|
||||
|
@ -26,23 +26,8 @@
|
|||
|
||||
<h3>New with this release</h3>
|
||||
<ul>
|
||||
<li>Complete and up-to-date translations into Dutch, French and
|
||||
Catalan. What language is next?</li>
|
||||
|
||||
<li>Allow copying invitation URL to clipboard so you can paste
|
||||
it into any messaging app you like</li>
|
||||
|
||||
<li>Improvements to in-game chat experience (but more are coming)</li>
|
||||
|
||||
<li>Show a "toast" when hint button can't find any moves</li>
|
||||
|
||||
<li>Add SMS to the list of ways you can invite somebody</li>
|
||||
|
||||
<li>When displaying Bluetooth-connected devices to invite, skip
|
||||
stuff like headphones</li>
|
||||
<li>Turn off email invite attachments. They didn't seem to work anyway,
|
||||
and aren't needed on modern Android.</li>
|
||||
<li>Fix very old memory leak</li>
|
||||
<li>Fix to send correctly calculated identifier for game
|
||||
state.</li>
|
||||
</ul>
|
||||
|
||||
<p>(The full changelog
|
||||
|
@ -51,8 +36,9 @@
|
|||
<h3>Next up</h3>
|
||||
<ul>
|
||||
<li>Offer "Rematch" when game's over (Easy via
|
||||
SMS and Bluetooth; harder via the internet/relay)</li>
|
||||
<li>Look into supporting play via peer-to-peer wifi</li>
|
||||
SMS and Bluetooth; harder via the internet/relay)</li>
|
||||
<li>Take advantage of Marshmallow's new permissions model (where
|
||||
the app only asks for them when it needs them.)
|
||||
</ul>
|
||||
|
||||
<p>Please let me know
|
||||
|
|
34
xwords4/android/XWords4/build.gradle
Normal file
34
xwords4/android/XWords4/build.gradle
Normal file
|
@ -0,0 +1,34 @@
|
|||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:1.3.0'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
|
||||
subprojects {
|
||||
afterEvaluate {project ->
|
||||
if (project.hasProperty("android")) {
|
||||
android {
|
||||
compileSdkVersion 14
|
||||
buildToolsVersion '22.0.1'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name="XWords4" default="release">
|
||||
|
||||
<!-- eeh: allow ant files to refer e.g. to ${env.HOME} -->
|
||||
<property environment="env" />
|
||||
|
||||
<!-- The local.properties file is created and updated by the 'android' tool.
|
||||
It contains the path to the SDK. It should *NOT* be checked into
|
||||
Version Control Systems. -->
|
||||
|
@ -52,7 +55,7 @@
|
|||
<!-- extension targets. Uncomment the ones where you want to do custom work
|
||||
in between standard targets -->
|
||||
|
||||
<property name="INITIAL_CLIENT_VERS" value="6"/>
|
||||
<property name="INITIAL_CLIENT_VERS" value="8"/>
|
||||
<property name="VARIANT_NAME" value="xw4"/>
|
||||
<property name="APP_NAME" value="Crosswords"/>
|
||||
|
||||
|
|
18
xwords4/android/XWords4/gradle.properties
Normal file
18
xwords4/android/XWords4/gradle.properties
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Project-wide Gradle settings.
|
||||
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
# Default value: -Xmx10248m -XX:MaxPermSize=256m
|
||||
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
||||
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
BIN
xwords4/android/XWords4/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
xwords4/android/XWords4/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
xwords4/android/XWords4/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
xwords4/android/XWords4/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
#Mon Nov 09 19:22:17 PST 2015
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip
|
164
xwords4/android/XWords4/gradlew
vendored
Executable file
164
xwords4/android/XWords4/gradlew
vendored
Executable file
|
@ -0,0 +1,164 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn ( ) {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die ( ) {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
esac
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched.
|
||||
if $cygwin ; then
|
||||
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
fi
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >&-
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >&-
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
}
|
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
90
xwords4/android/XWords4/gradlew.bat
vendored
Normal file
90
xwords4/android/XWords4/gradlew.bat
vendored
Normal file
|
@ -0,0 +1,90 @@
|
|||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windowz variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
goto execute
|
||||
|
||||
:4NT_args
|
||||
@rem Get arguments from the 4NT Shell from JP Software
|
||||
set CMD_LINE_ARGS=%$
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
|
@ -39,6 +39,7 @@ LOCAL_DEFINES += \
|
|||
-DXWFEATURE_BASE64 \
|
||||
-DXWFEATURE_DEVID \
|
||||
-DCOMMON_LAYOUT \
|
||||
-DNATIVE_NLI \
|
||||
-DCOMMS_VERSION=1 \
|
||||
-DINITIAL_CLIENT_VERS=${INITIAL_CLIENT_VERS} \
|
||||
-DVARIANT_${VARIANT} \
|
||||
|
@ -84,7 +85,7 @@ COMMON_SRC_FILES += \
|
|||
$(COMMON_PATH)/memstream.c \
|
||||
$(COMMON_PATH)/movestak.c \
|
||||
$(COMMON_PATH)/dbgutil.c \
|
||||
|
||||
$(COMMON_PATH)/nli.c \
|
||||
|
||||
LOCAL_CFLAGS+=$(LOCAL_C_INCLUDES) $(LOCAL_DEFINES) -Wall -std=c99
|
||||
LOCAL_SRC_FILES := $(linux_SRC_FILES) $(LOCAL_SRC_FILES) $(COMMON_SRC_FILES)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* -*- compile-command: "cd ..; ../scripts/ndkbuild.sh -j3"; -*- */
|
||||
/* -*- compile-command: "find-and-ant.sh debug install"; -*- */
|
||||
/*
|
||||
* Copyright © 2009 - 2011 by Eric House (xwords@eehouse.org). All rights
|
||||
* Copyright © 2009 - 2016 by Eric House (xwords@eehouse.org). All rights
|
||||
* reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -648,7 +648,7 @@ makeDict( MPFORMAL JNIEnv *env, DictMgrCtxt* dictMgr, JNIUtilCtxt* jniutil, jstr
|
|||
anddict->super.langName = getStringCopy( MPPARM(mpool)
|
||||
env, jlangname );
|
||||
|
||||
XP_U32 numEdges;
|
||||
XP_U32 numEdges = 0;
|
||||
XP_Bool parses = parseDict( anddict, (XP_U8*)anddict->bytes,
|
||||
bytesSize, &numEdges );
|
||||
if ( !parses || (check && !checkSanity( &anddict->super,
|
||||
|
|
|
@ -78,12 +78,14 @@ error error error
|
|||
int
|
||||
getInt( JNIEnv* env, jobject obj, const char* name )
|
||||
{
|
||||
// XP_LOGF( "%s(name=%s)", __func__, name );
|
||||
jclass cls = (*env)->GetObjectClass( env, obj );
|
||||
XP_ASSERT( !!cls );
|
||||
jfieldID fid = (*env)->GetFieldID( env, cls, name, "I");
|
||||
XP_ASSERT( !!fid );
|
||||
int result = (*env)->GetIntField( env, obj, fid );
|
||||
deleteLocalRef( env, cls );
|
||||
// XP_LOGF( "%s(name=%s) => %d", __func__, name, result );
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -113,12 +115,14 @@ getInts( JNIEnv* env, void* cobj, jobject jobj, const SetInfo* sis, XP_U16 nSis
|
|||
void
|
||||
setInt( JNIEnv* env, jobject obj, const char* name, int value )
|
||||
{
|
||||
// XP_LOGF( "%s(name=%s)", __func__, name );
|
||||
jclass cls = (*env)->GetObjectClass( env, obj );
|
||||
XP_ASSERT( !!cls );
|
||||
jfieldID fid = (*env)->GetFieldID( env, cls, name, "I");
|
||||
XP_ASSERT( !!fid );
|
||||
(*env)->SetIntField( env, obj, fid, value );
|
||||
deleteLocalRef( env, cls );
|
||||
// XP_LOGF( "%s(name=%s) DONE", __func__, name );
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -178,6 +182,7 @@ setBools( JNIEnv* env, jobject jobj, void* cobj, const SetInfo* sis, XP_U16 nSis
|
|||
bool
|
||||
setString( JNIEnv* env, jobject obj, const char* name, const XP_UCHAR* value )
|
||||
{
|
||||
// XP_LOGF( "%s(%s)", __func__, name );
|
||||
bool success = false;
|
||||
jclass cls = (*env)->GetObjectClass( env, obj );
|
||||
jfieldID fid = (*env)->GetFieldID( env, cls, name, "Ljava/lang/String;" );
|
||||
|
@ -193,10 +198,32 @@ setString( JNIEnv* env, jobject obj, const char* name, const XP_UCHAR* value )
|
|||
return success;
|
||||
}
|
||||
|
||||
void
|
||||
getStrings( JNIEnv* env, void* cobj, jobject jobj, const SetInfo* sis, XP_U16 nSis )
|
||||
{
|
||||
for ( int ii = 0; ii < nSis; ++ii ) {
|
||||
const SetInfo* si = &sis[ii];
|
||||
XP_UCHAR* buf = (XP_UCHAR*)(((uint8_t*)cobj) + si->offset);
|
||||
getString( env, jobj, si->name, buf, si->siz );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
setStrings( JNIEnv* env, jobject jobj, void* cobj, const SetInfo* sis, XP_U16 nSis )
|
||||
{
|
||||
for ( int ii = 0; ii < nSis; ++ii ) {
|
||||
const SetInfo* si = &sis[ii];
|
||||
// XP_LOGF( "calling setString(%s)", si->name );
|
||||
XP_UCHAR* val = (XP_UCHAR*)(((uint8_t*)cobj) + si->offset);
|
||||
setString( env, jobj, si->name, val );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
getString( JNIEnv* env, jobject obj, const char* name, XP_UCHAR* buf,
|
||||
int bufLen )
|
||||
{
|
||||
// XP_LOGF( "%s(%s)", __func__, name );
|
||||
jclass cls = (*env)->GetObjectClass( env, obj );
|
||||
XP_ASSERT( !!cls );
|
||||
jfieldID fid = (*env)->GetFieldID( env, cls, name, "Ljava/lang/String;" );
|
||||
|
@ -214,6 +241,7 @@ getString( JNIEnv* env, jobject obj, const char* name, XP_UCHAR* buf,
|
|||
buf[len] = '\0';
|
||||
|
||||
deleteLocalRef( env, cls );
|
||||
// XP_LOGF( "%s(%s) DONE", __func__, name );
|
||||
}
|
||||
|
||||
XP_UCHAR*
|
||||
|
@ -403,9 +431,15 @@ getMethodID( JNIEnv* env, jobject obj, const char* proc, const char* sig )
|
|||
XP_ASSERT( !!env );
|
||||
jclass cls = (*env)->GetObjectClass( env, obj );
|
||||
XP_ASSERT( !!cls );
|
||||
#ifdef DEBUG
|
||||
char buf[128] = {0};
|
||||
/* int len = sizeof(buf); */
|
||||
/* getClassName( env, obj, buf, &len ); */
|
||||
#endif
|
||||
jmethodID mid = (*env)->GetMethodID( env, cls, proc, sig );
|
||||
if ( !mid ) {
|
||||
XP_LOGF( "%s: no mid for proc %s, sig %s", __func__, proc, sig );
|
||||
XP_LOGF( "%s: no mid for proc %s, sig %s in object of class %s",
|
||||
__func__, proc, sig, buf );
|
||||
}
|
||||
XP_ASSERT( !!mid );
|
||||
deleteLocalRef( env, cls );
|
||||
|
@ -703,8 +737,46 @@ android_debugf( const char* format, ... )
|
|||
# endif
|
||||
, buf );
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Print an object's class name into buffer.
|
||||
*
|
||||
* NOTE: this must be called in advance of any jni error, because methods on
|
||||
* env can't be called once there's an exception pending.
|
||||
*/
|
||||
#if 0
|
||||
static void
|
||||
getClassName( JNIEnv* env, jobject obj, char* out, int* outLen )
|
||||
{
|
||||
XP_ASSERT( !!obj );
|
||||
jclass cls1 = (*env)->GetObjectClass( env, obj );
|
||||
|
||||
// First get the class object
|
||||
jmethodID mid = (*env)->GetMethodID( env, cls1, "getClass",
|
||||
"()Ljava/lang/Class;" );
|
||||
jobject clsObj = (*env)->CallObjectMethod( env, obj, mid );
|
||||
|
||||
// Now get the class object's class descriptor
|
||||
jclass cls2 = (*env)->GetObjectClass( env, clsObj );
|
||||
// Find the getName() method on the class object
|
||||
mid = (*env)->GetMethodID( env, cls2, "getName", "()Ljava/lang/String;" );
|
||||
|
||||
// Call the getName() to get a jstring object back
|
||||
jstring strObj = (jstring)(*env)->CallObjectMethod( env, clsObj, mid );
|
||||
|
||||
jint slen = (*env)->GetStringUTFLength( env, strObj );
|
||||
if ( slen < *outLen ) {
|
||||
*outLen = slen;
|
||||
(*env)->GetStringUTFRegion( env, strObj, 0, slen, out );
|
||||
out[slen] = '\0';
|
||||
} else {
|
||||
*outLen = 0;
|
||||
out[0] = '\0';
|
||||
}
|
||||
deleteLocalRefs( env, clsObj, cls1, cls2, strObj, DELETE_NO_REF );
|
||||
LOG_RETURNF( "%s", out );
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* #ifdef DEBUG */
|
||||
/* XP_U32 */
|
||||
|
|
|
@ -58,6 +58,10 @@ void setBools( JNIEnv* env, jobject jobj, void* cobj,
|
|||
bool setString( JNIEnv* env, jobject obj, const char* name, const XP_UCHAR* value );
|
||||
void getString( JNIEnv* env, jobject jlp, const char* name, XP_UCHAR* buf,
|
||||
int bufLen );
|
||||
void getStrings( JNIEnv* env, void* cobj, jobject jobj,
|
||||
const SetInfo* sis, XP_U16 nSis );
|
||||
void setStrings( JNIEnv* env, jobject jobj, void* cobj,
|
||||
const SetInfo* sis, XP_U16 nSis );
|
||||
XP_UCHAR* getStringCopy( MPFORMAL JNIEnv* env, jstring jname );
|
||||
void setObject( JNIEnv* env, jobject obj, const char* name, const char* sig,
|
||||
jobject val );
|
||||
|
|
|
@ -66,15 +66,16 @@ and_xport_getFlags( void* closure )
|
|||
}
|
||||
|
||||
static XP_S16
|
||||
and_xport_send( const XP_U8* buf, XP_U16 len, const CommsAddrRec* addr,
|
||||
CommsConnType conType, XP_U32 gameID, void* closure )
|
||||
and_xport_send( const XP_U8* buf, XP_U16 len, const XP_UCHAR* msgNo,
|
||||
const CommsAddrRec* addr, CommsConnType conType,
|
||||
XP_U32 gameID, void* closure )
|
||||
{
|
||||
jint result = -1;
|
||||
LOG_FUNC();
|
||||
AndTransportProcs* aprocs = (AndTransportProcs*)closure;
|
||||
if ( NULL != aprocs->jxport ) {
|
||||
JNIEnv* env = ENVFORME( aprocs->ti );
|
||||
const char* sig = "([BL" PKG_PATH("jni/CommsAddrRec")
|
||||
const char* sig = "([BLjava/lang/String;L" PKG_PATH("jni/CommsAddrRec")
|
||||
";L" PKG_PATH("jni/CommsAddrRec$CommsConnType") ";I)I";
|
||||
|
||||
jmethodID mid = getMethodID( env, aprocs->jxport, "transportSend", sig );
|
||||
|
@ -83,15 +84,15 @@ and_xport_send( const XP_U8* buf, XP_U16 len, const CommsAddrRec* addr,
|
|||
jobject jaddr = makeJAddr( env, addr );
|
||||
jobject jConType =
|
||||
intToJEnum(env, conType, PKG_PATH("jni/CommsAddrRec$CommsConnType"));
|
||||
jstring jMsgNo = !!msgNo ? (*env)->NewStringUTF( env, msgNo ) : NULL;
|
||||
result = (*env)->CallIntMethod( env, aprocs->jxport, mid,
|
||||
jbytes, jaddr, jConType, gameID );
|
||||
deleteLocalRefs( env, jaddr, jbytes, jConType, DELETE_NO_REF );
|
||||
jbytes, jMsgNo, jaddr, jConType, gameID );
|
||||
deleteLocalRefs( env, jaddr, jbytes, jMsgNo, jConType, DELETE_NO_REF );
|
||||
}
|
||||
LOG_RETURNF( "%d", result );
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
and_xport_relayStatus( void* closure, CommsRelayState newState )
|
||||
{
|
||||
|
@ -126,7 +127,7 @@ and_xport_relayConnd( void* closure, XP_UCHAR* const room, XP_Bool reconnect,
|
|||
}
|
||||
|
||||
static XP_Bool
|
||||
and_xport_sendNoConn( const XP_U8* buf, XP_U16 len,
|
||||
and_xport_sendNoConn( const XP_U8* buf, XP_U16 len, const XP_UCHAR* msgNo,
|
||||
const XP_UCHAR* relayID, void* closure )
|
||||
{
|
||||
jboolean result = false;
|
||||
|
@ -134,14 +135,15 @@ and_xport_sendNoConn( const XP_U8* buf, XP_U16 len,
|
|||
if ( NULL != aprocs && NULL != aprocs->jxport ) {
|
||||
JNIEnv* env = ENVFORME( aprocs->ti );
|
||||
|
||||
const char* sig = "([BLjava/lang/String;)Z";
|
||||
const char* sig = "([BLjava/lang/String;Ljava/lang/String;)Z";
|
||||
jmethodID mid = getMethodID( env, aprocs->jxport,
|
||||
"relayNoConnProc", sig );
|
||||
jbyteArray jbytes = makeByteArray( env, len, (jbyte*)buf );
|
||||
jstring jRelayID = (*env)->NewStringUTF( env, relayID );
|
||||
jstring jMsgNo = !!msgNo ? (*env)->NewStringUTF( env, msgNo ) : NULL;
|
||||
result = (*env)->CallBooleanMethod( env, aprocs->jxport, mid,
|
||||
jbytes, jRelayID );
|
||||
deleteLocalRefs( env, jbytes, jRelayID, DELETE_NO_REF );
|
||||
jbytes, jMsgNo, jRelayID );
|
||||
deleteLocalRefs( env, jbytes, jRelayID, jMsgNo, DELETE_NO_REF );
|
||||
}
|
||||
LOG_RETURNF( "%d", result );
|
||||
return result;
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "dictnry.h"
|
||||
#include "dictiter.h"
|
||||
#include "dictmgr.h"
|
||||
#include "nli.h"
|
||||
|
||||
#include "utilwrapper.h"
|
||||
#include "drawwrapper.h"
|
||||
|
@ -283,6 +284,46 @@ makeGI( MPFORMAL JNIEnv* env, jobject jgi )
|
|||
return gi;
|
||||
} /* makeGI */
|
||||
|
||||
static const SetInfo nli_ints[] = {
|
||||
ARR_MEMBER( NetLaunchInfo, _conTypes ),
|
||||
ARR_MEMBER( NetLaunchInfo, lang ),
|
||||
ARR_MEMBER( NetLaunchInfo, forceChannel ),
|
||||
ARR_MEMBER( NetLaunchInfo, nPlayersT ),
|
||||
ARR_MEMBER( NetLaunchInfo, nPlayersH ),
|
||||
ARR_MEMBER( NetLaunchInfo, gameID ),
|
||||
ARR_MEMBER( NetLaunchInfo, osVers ),
|
||||
};
|
||||
|
||||
static const SetInfo nli_bools[] = {
|
||||
ARR_MEMBER( NetLaunchInfo, isGSM )
|
||||
};
|
||||
|
||||
static const SetInfo nli_strs[] = {
|
||||
ARR_MEMBER( NetLaunchInfo, dict ),
|
||||
ARR_MEMBER( NetLaunchInfo, gameName ),
|
||||
ARR_MEMBER( NetLaunchInfo, room ),
|
||||
ARR_MEMBER( NetLaunchInfo, btName ),
|
||||
ARR_MEMBER( NetLaunchInfo, btAddress ),
|
||||
ARR_MEMBER( NetLaunchInfo, phone ),
|
||||
ARR_MEMBER( NetLaunchInfo, inviteID ),
|
||||
};
|
||||
|
||||
static void
|
||||
loadNLI( JNIEnv* env, NetLaunchInfo* nli, jobject jnli )
|
||||
{
|
||||
getInts( env, (void*)nli, jnli, nli_ints, VSIZE(nli_ints) );
|
||||
getBools( env, (void*)nli, jnli, nli_bools, VSIZE(nli_bools) );
|
||||
getStrings( env, (void*)nli, jnli, nli_strs, VSIZE(nli_strs) );
|
||||
}
|
||||
|
||||
static void
|
||||
setNLI( JNIEnv* env, jobject jnli, const NetLaunchInfo* nli )
|
||||
{
|
||||
setInts( env, jnli, (void*)nli, nli_ints, VSIZE(nli_ints) );
|
||||
setBools( env, jnli, (void*)nli, nli_bools, VSIZE(nli_bools) );
|
||||
setStrings( env, jnli, (void*)nli, nli_strs, VSIZE(nli_strs) );
|
||||
}
|
||||
|
||||
static void
|
||||
setJGI( JNIEnv* env, jobject jgi, const CurGameInfo* gi )
|
||||
{
|
||||
|
@ -453,6 +494,59 @@ Java_org_eehouse_android_xw4_jni_XwJNI_gi_1from_1stream
|
|||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_nli_1to_1stream
|
||||
( JNIEnv* env, jclass C, jobject njli )
|
||||
{
|
||||
LOG_FUNC();
|
||||
jbyteArray result;
|
||||
#ifdef MEM_DEBUG
|
||||
MemPoolCtx* mpool = mpool_make( NULL );
|
||||
#endif
|
||||
NetLaunchInfo nli = {0};
|
||||
loadNLI( env, &nli, njli );
|
||||
/* CurGameInfo* gi = makeGI( MPPARM(mpool) env, jgi ); */
|
||||
VTableMgr* vtMgr = make_vtablemgr( MPPARM_NOCOMMA(mpool) );
|
||||
XWStreamCtxt* stream = mem_stream_make( MPPARM(mpool) vtMgr,
|
||||
NULL, 0, NULL );
|
||||
|
||||
nli_saveToStream( &nli, stream );
|
||||
|
||||
result = streamToBArray( env, stream );
|
||||
stream_destroy( stream );
|
||||
|
||||
vtmgr_destroy( MPPARM(mpool) vtMgr );
|
||||
#ifdef MEM_DEBUG
|
||||
mpool_destroy( mpool );
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_nli_1from_1stream
|
||||
( JNIEnv* env, jclass C, jobject jnli, jbyteArray jstream )
|
||||
{
|
||||
LOG_FUNC();
|
||||
#ifdef MEM_DEBUG
|
||||
MemPoolCtx* mpool = mpool_make( NULL );
|
||||
#endif
|
||||
VTableMgr* vtMgr = make_vtablemgr( MPPARM_NOCOMMA(mpool) );
|
||||
XWStreamCtxt* stream = streamFromJStream( MPPARM(mpool) env, vtMgr, jstream );
|
||||
|
||||
NetLaunchInfo nli = {0};
|
||||
if ( nli_makeFromStream( &nli, stream ) ) {
|
||||
setNLI( env, jnli, &nli );
|
||||
} else {
|
||||
XP_LOGF( "%s: game_makeFromStream failed", __func__ );
|
||||
}
|
||||
|
||||
stream_destroy( stream );
|
||||
vtmgr_destroy( MPPARM(mpool) vtMgr );
|
||||
#ifdef MEM_DEBUG
|
||||
mpool_destroy( mpool );
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_comms_1getInitialAddr
|
||||
( JNIEnv* env, jclass C, jobject jaddr, jstring jname, jint port )
|
||||
|
@ -1730,6 +1824,25 @@ Java_org_eehouse_android_xw4_jni_XwJNI_comms_1isConnected
|
|||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_comms_1formatRelayID
|
||||
( JNIEnv* env, jclass C, jint gamePtr, jint indx )
|
||||
{
|
||||
jstring result = NULL;
|
||||
XWJNI_START();
|
||||
|
||||
XP_UCHAR buf[64];
|
||||
XP_U16 len = sizeof(buf);
|
||||
if ( comms_formatRelayID( state->game.comms, indx, buf, &len ) ) {
|
||||
XP_ASSERT( len < sizeof(buf) );
|
||||
LOG_RETURNF( "%s", buf );
|
||||
result = (*env)->NewStringUTF( env, buf );
|
||||
}
|
||||
|
||||
XWJNI_END();
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_comms_1getStats
|
||||
( JNIEnv* env, jclass C, jint gamePtr )
|
||||
|
|
2
xwords4/android/XWords4/libs/.gitignore
vendored
Normal file
2
xwords4/android/XWords4/libs/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/armeabi
|
||||
/x86
|
|
@ -23,6 +23,7 @@
|
|||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/game_locked"
|
||||
android:checked="true"
|
||||
android:visibility="gone"
|
||||
android:layout_alignParentTop="true"
|
||||
/>
|
||||
|
|
52
xwords4/android/XWords4/res/layout/relayinviter.xml
Normal file
52
xwords4/android/XWords4/res/layout/relayinviter.xml
Normal file
|
@ -0,0 +1,52 @@
|
|||
<?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"
|
||||
>
|
||||
|
||||
<TextView android:id="@+id/invite_desc"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:padding="8dp"
|
||||
/>
|
||||
|
||||
<ListView android:id="@id/android:list"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:drawSelectorOnTop="false"
|
||||
android:layout_weight="1"
|
||||
android:padding="8dp"
|
||||
/>
|
||||
|
||||
<TextView android:id="@android:id/empty"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/empty_relay_inviter"
|
||||
android:padding="20dp"
|
||||
/>
|
||||
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
>
|
||||
<Button android:id="@+id/button_add"
|
||||
android:text="@string/button_relay_add"
|
||||
style="@style/evenly_spaced_horizontal"
|
||||
/>
|
||||
<Button android:id="@+id/button_clear"
|
||||
android:text="@string/bt_pick_clear_button"
|
||||
style="@style/evenly_spaced_horizontal"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<Button android:id="@+id/button_invite"
|
||||
android:text="@string/button_invite"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dip"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
|
@ -5,6 +5,10 @@
|
|||
<group android:id="@+id/group_done">
|
||||
<!-- title set in BoardActivity -->
|
||||
|
||||
<item android:id="@+id/board_menu_rematch"
|
||||
android:title="@string/button_rematch"
|
||||
android:showAsAction="ifRoom"
|
||||
/>
|
||||
<item android:id="@+id/board_menu_done"
|
||||
android:alphabeticShortcut="D"
|
||||
android:showAsAction="ifRoom"
|
||||
|
|
34
xwords4/android/XWords4/res/menu/games_list_game_menu.xml
Normal file
34
xwords4/android/XWords4/res/menu/games_list_game_menu.xml
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:id="@+id/games_game_delete"
|
||||
android:title="@string/list_item_delete"
|
||||
/>
|
||||
<item android:id="@+id/games_game_rematch"
|
||||
android:title="@string/button_rematch"
|
||||
/>
|
||||
<item android:id="@+id/games_game_config"
|
||||
android:title="@string/list_item_config"
|
||||
/>
|
||||
<item android:id="@+id/games_game_move"
|
||||
android:title="@string/list_item_move"
|
||||
/>
|
||||
<item android:id="@+id/games_game_reset"
|
||||
android:title="@string/list_item_reset"
|
||||
/>
|
||||
<item android:id="@+id/games_game_new_from"
|
||||
android:title="@string/list_item_new_from"
|
||||
/>
|
||||
<item android:id="@+id/games_game_rename"
|
||||
android:title="@string/list_item_rename"
|
||||
/>
|
||||
<item android:id="@+id/games_game_copy"
|
||||
android:title="@string/list_item_copy"
|
||||
/>
|
||||
<item android:id="@+id/games_game_select"
|
||||
android:title="@string/list_item_select"
|
||||
/>
|
||||
<item android:id="@+id/games_game_deselect"
|
||||
android:title="@string/list_item_deselect"
|
||||
/>
|
||||
</menu>
|
25
xwords4/android/XWords4/res/menu/games_list_group_menu.xml
Normal file
25
xwords4/android/XWords4/res/menu/games_list_group_menu.xml
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:id="@+id/games_game_select"
|
||||
android:title="@string/list_item_select"
|
||||
/>
|
||||
<item android:id="@+id/games_game_deselect"
|
||||
android:title="@string/list_item_deselect"
|
||||
/>
|
||||
<item android:id="@+id/games_group_moveup"
|
||||
android:title="@string/list_group_moveup"
|
||||
/>
|
||||
<item android:id="@+id/games_group_movedown"
|
||||
android:title="@string/list_group_movedown"
|
||||
/>
|
||||
<item android:id="@+id/games_group_delete"
|
||||
android:title="@string/list_group_delete"
|
||||
/>
|
||||
<item android:id="@+id/games_group_default"
|
||||
android:title="@string/list_group_default"
|
||||
/>
|
||||
<item android:id="@+id/games_group_rename"
|
||||
android:title="@string/list_group_rename"
|
||||
/>
|
||||
</menu>
|
|
@ -57,6 +57,9 @@
|
|||
android:icon="@drawable/content_discard__gen"
|
||||
android:showAsAction="ifRoom"
|
||||
/>
|
||||
<item android:id="@+id/games_game_rematch"
|
||||
android:title="@string/button_rematch"
|
||||
/>
|
||||
<item android:id="@+id/games_game_config"
|
||||
android:title="@string/list_item_config"
|
||||
android:icon="@drawable/content_edit"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<resources>
|
||||
<string name="app_version">4.4 beta 98</string>
|
||||
<string name="app_version">4.4 beta 101</string>
|
||||
</resources>
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
<!-- Resources in this file do not require localization -->
|
||||
<resources>
|
||||
|
||||
<!-- prefs keys -->
|
||||
<string name="key_color_tiles">key_color_tiles</string>
|
||||
<string name="key_show_arrow">key_show_arrow</string>
|
||||
|
@ -10,6 +9,7 @@
|
|||
<string name="key_explain_robot">key_explain_robot</string>
|
||||
<string name="key_skip_confirm">key_skip_confirm</string>
|
||||
<string name="key_disable_nag">key_disable_nag</string>
|
||||
<string name="key_disable_nag_solo">key_disable_nag_solo</string>
|
||||
<string name="key_sort_tiles">key_sort_tiles</string>
|
||||
<string name="key_peek_other">key_peek_other</string>
|
||||
<string name="key_hide_crosshairs">key_hide_crosshairs</string>
|
||||
|
@ -73,6 +73,7 @@
|
|||
<string name="key_closed_langs">key_closed_langs</string>
|
||||
<string name="key_bt_addrs">key_bt_addrs</string>
|
||||
<string name="key_sms_phones">key_sms_phones</string>
|
||||
<string name="key_relay_ids">key_relay_ids</string>
|
||||
<string name="key_connstat_data">key_connstat_data</string>
|
||||
<string name="key_dev_id">key_dev_id</string>
|
||||
|
||||
|
@ -119,6 +120,7 @@
|
|||
<string name="key_enable_dup_invite">key_enable_dup_invite</string>
|
||||
<string name="key_enable_nfc_toself">key_enable_nfc_toself</string>
|
||||
<string name="key_enable_sms_toself">key_enable_sms_toself</string>
|
||||
<string name="key_enable_relay_toself">key_enable_relay_toself</string>
|
||||
<string name="key_nag_intervals">key_nag_intervals</string>
|
||||
<string name="key_download_path">key_download_path</string>
|
||||
<string name="key_got_langdict">key_got_langdict</string>
|
||||
|
@ -126,6 +128,8 @@
|
|||
<string name="key_xlations_enabled">key_xlations_enabled</string>
|
||||
<string name="key_invite_multi">key_invite_multi</string>
|
||||
<string name="key_notagain_enablepublic">key_notagain_enablepublic</string>
|
||||
<string name="key_na_rematch_two_only">key_notagain_rematch_two_only</string>
|
||||
<string name="key_notagain_dfltname">key_notagain_dfltname</string>
|
||||
|
||||
<string name="key_na_comms_bt">key_na_comms_bt</string>
|
||||
<string name="key_na_comms_sms">key_na_comms_sms</string>
|
||||
|
@ -263,7 +267,7 @@
|
|||
<!-- -->
|
||||
<item>DIEC</item>
|
||||
<item>:ca:</item>
|
||||
<item>http://mdlc.iec.cat/results.asp?txtEntrada=%2$s</item>
|
||||
<item>http://diccionari.totescrable.cat/cercador/?mot=%2$s</item>
|
||||
<!-- -->
|
||||
<item>Viccionari</item>
|
||||
<item>:ca:</item>
|
||||
|
|
|
@ -163,7 +163,7 @@
|
|||
|
||||
<plurals name="confirm_seldeletes_fmt">
|
||||
<item quantity="one">Are you sure you want to delete
|
||||
the %1$d selected game? This action cannot be undone.</item>
|
||||
the selected game? This action cannot be undone.</item>
|
||||
<item quantity="other">Are you sure you want to delete
|
||||
the %1$d selected games? This action cannot be undone.</item>
|
||||
</plurals>
|
||||
|
@ -171,7 +171,7 @@
|
|||
<!-- Text of confirmation dialog posted when list_item_reset menu
|
||||
is selected -->
|
||||
<plurals name="confirm_reset_fmt">
|
||||
<item quantity="one">Are you sure you want to reset the %1$d
|
||||
<item quantity="one">Are you sure you want to reset the
|
||||
selected game?\n\n(Resetting erases all moves and any connection
|
||||
information.)</item>
|
||||
<item quantity="other">Are you sure you want to reset the %1$d
|
||||
|
@ -696,7 +696,7 @@
|
|||
because users should not have to do do this EVER. -->
|
||||
<string name="board_menu_game_resend">Resend messages</string>
|
||||
<plurals name="resend_finished_fmt">
|
||||
<item quantity="one">Resend finished; sent %1$d message.</item>
|
||||
<item quantity="one">Resend finished; sent one message.</item>
|
||||
<item quantity="other">Resend finished; sent %1$d messages.</item>
|
||||
</plurals>
|
||||
|
||||
|
@ -1191,6 +1191,7 @@
|
|||
<string name="invite_choice_email">Email</string>
|
||||
<string name="invite_choice_bt">Bluetooth</string>
|
||||
<string name="invite_choice_nfc">NFC (\"Android beaming\")</string>
|
||||
<string name="invite_choice_relay">Internet/Relay</string>
|
||||
<string name="invite_choice_title">Inviting players: How?</string>
|
||||
<!-- <string name="sms_or_email">Send invitation using SMS (texting) or -->
|
||||
<!-- via email?</string> -->
|
||||
|
@ -1719,12 +1720,11 @@
|
|||
-->
|
||||
|
||||
<!-- Welcome dialog title -->
|
||||
<string name="default_name_title">Welcome</string>
|
||||
<string name="default_name_title">Default player name</string>
|
||||
<!-- Welcome dialog text -->
|
||||
<string name="default_name_message">Thanks for installing
|
||||
Crosswords!\n\nFeel free to enter your name here. It will be used
|
||||
when creating new games. (You can change it later in the \"New
|
||||
game default\" section of Settings.)</string>
|
||||
<string name="default_name_message">Please enter your name
|
||||
here. It will be used when creating new games. (You can change it
|
||||
later in the \"New game default\" section of Settings.)</string>
|
||||
|
||||
<!--
|
||||
###########################################################
|
||||
|
@ -1738,7 +1738,7 @@
|
|||
<string name="about_vers_fmt">Crosswords for Android, Version %1$s,
|
||||
rev %2$s, built on %3$s.</string>
|
||||
<!-- copyright info -->
|
||||
<string name="about_copyright">Copyright (C) 1998-2015 by Eric
|
||||
<string name="about_copyright">Copyright (C) 1998-2016 by Eric
|
||||
House. This free/open source software is released under the GNU Public
|
||||
License.</string>
|
||||
|
||||
|
@ -1865,9 +1865,12 @@
|
|||
<!-- -->
|
||||
<string name="summary_conn">Game in play</string>
|
||||
<!-- -->
|
||||
<string name="new_bt_title">New game via Bluetooth</string>
|
||||
<string name="invite_notice_title">New game via Invitation</string>
|
||||
<!-- -->
|
||||
<string name="new_bt_body_fmt">A player on the device %1$s wants to start a game</string>
|
||||
<string name="new_relay_body">Tap to open the new game</string>
|
||||
|
||||
|
||||
<!-- -->
|
||||
<string name="bt_bad_proto_fmt">The version of Crosswords on
|
||||
\"%1$s\" is incompatible with this one for play using
|
||||
|
@ -1905,6 +1908,7 @@
|
|||
<string name="bt_invite_title">Bluetooth Invitation</string>
|
||||
<!-- Title of phone number picker during invitation to a game via SMS -->
|
||||
<string name="sms_invite_title">SMS Invitation</string>
|
||||
<string name="relay_invite_title">Relay Invitation</string>
|
||||
|
||||
<!-- -->
|
||||
<string name="game_btname_title">Bluetooth game name</string>
|
||||
|
@ -1921,12 +1925,12 @@
|
|||
<!-- -->
|
||||
<string name="dft_sms_name_fmt">SMS Game %1$X</string>
|
||||
<!-- -->
|
||||
<string name="new_sms_title">New game via SMS</string>
|
||||
<!-- -->
|
||||
<string name="new_name_body_fmt">%1$s has invited you to play</string>
|
||||
<!-- -->
|
||||
<string name="button_sms_add">Import contact</string>
|
||||
<!-- -->
|
||||
<string name="button_relay_add">Scan games</string>
|
||||
<!-- -->
|
||||
<plurals name="invite_sms_desc_fmt">
|
||||
<item quantity="one">Please check the phone number you want to
|
||||
invite to your new game, then tap \"%2$s\".</item>
|
||||
|
@ -1934,6 +1938,13 @@
|
|||
want to invite to your new game, then tap \"%2$s\".</item>
|
||||
</plurals>
|
||||
<!-- -->
|
||||
<plurals name="invite_relay_desc_fmt">
|
||||
<item quantity="one">Please check the device you want to invite
|
||||
to your new game, then tap \"%2$s\".</item>
|
||||
<item quantity="other">Please check the %1$d devices you want to invite
|
||||
to your new game, then tap \"%2$s\".</item>
|
||||
</plurals>
|
||||
<!-- -->
|
||||
<string name="manual_owner_name">(Not in contacts)</string>
|
||||
<!-- -->
|
||||
<string name="warn_nomobile_fmt">The number %1$s for %2$s is not
|
||||
|
@ -1943,14 +1954,21 @@
|
|||
\"Import contact\" button to add people you want to invite, the +
|
||||
button to enter numbers directly.</string>
|
||||
<!-- -->
|
||||
<string name="get_sms_number">Enter phone number:</string>
|
||||
<string name="empty_relay_inviter">This list of devies is
|
||||
empty. Use the \"Scan games\" button to scan your old games
|
||||
for opponents. Use the + button to enter device IDs directly.</string>
|
||||
<!-- -->
|
||||
<plurals name="confirm_clear_fmt">
|
||||
<string name="get_sms_number">Enter phone number:</string>
|
||||
<string name="get_relay_number">Enter device ID:</string>
|
||||
<!-- -->
|
||||
<plurals name="confirm_clear_sms_fmt">
|
||||
<item quantity="one">Are you sure you want to delete the checked
|
||||
phone number?</item>
|
||||
<item quantity="other">Are you sure you want to delete the
|
||||
%1$d checked phone numbers?</item>
|
||||
</plurals>
|
||||
<string name="confirm_clear_relay">Are you sure you want to delete the
|
||||
checked device[s]?</string>
|
||||
<!-- -->
|
||||
<string name="connect_label_sms">Connection (via SMS/text)</string>
|
||||
<!-- -->
|
||||
|
@ -2379,6 +2397,7 @@
|
|||
|
||||
<string name="new_game">New one-device game</string>
|
||||
<string name="new_game_networked">New networked game</string>
|
||||
<string name="rematch_name_fmt">Rematch: %1$s</string>
|
||||
|
||||
<string name="new_game_message">Would you like to create this game
|
||||
using default settings?\n\nOr would you like to configure it
|
||||
|
@ -2419,6 +2438,8 @@
|
|||
</string>
|
||||
|
||||
<string name="waiting_title">Waiting for players</string>
|
||||
<!-- Button for alert with title above -->
|
||||
<string name="button_wait">Wait</string>
|
||||
|
||||
<string name="invite_stays">(This dialog will stay up until all
|
||||
remote players have connected. You can close the game if you
|
||||
|
@ -2450,9 +2471,11 @@
|
|||
and want them back, enable them now. You can turn them off again
|
||||
in Settings.</string>
|
||||
|
||||
<string name="disable_nag_title">Disable turn reminders</string>
|
||||
<string name="disable_nags_title">Turn reminders</string>
|
||||
<string name="disable_nag_title">Disable network game reminders</string>
|
||||
<string name="disable_nag_summary">Do not notify me no matter
|
||||
how long it\'s been my turn</string>
|
||||
<string name="disable_nag_solo_title">Disable solo game reminders</string>
|
||||
|
||||
<string name="confirm_get_locdict_fmt">Your device is set up for
|
||||
%1$s. Would you like to download a wordlist so you can play
|
||||
|
@ -2476,6 +2499,7 @@
|
|||
<string name="netstats_title">Game network stats</string>
|
||||
|
||||
<string name="git_rev_title">Source version id</string>
|
||||
<string name="devid_title">Device ID (on relay)</string>
|
||||
<string name="relay_port">Relay game port</string>
|
||||
<string name="proxy_port">Relay device port</string>
|
||||
<string name="name_dict_fmt">%1$s/%2$s</string>
|
||||
|
@ -2562,6 +2586,14 @@
|
|||
|
||||
<string name="str_no_hint_found">Cannot find any moves</string>
|
||||
|
||||
<string name="not_again_rematch_two_only">The Rematch button is
|
||||
disabled because, for now anyway, rematch is limited to two-person
|
||||
games. I think it\'s rare that people play with more than two. Let
|
||||
me know if I\'m wrong and I\'ll try harder to make it work.</string>
|
||||
|
||||
<string name="enable_relay_toself_title">Enable relay invites to self</string>
|
||||
<string name="enable_relay_toself_summary">(To aid testing and debugging)</string>
|
||||
|
||||
<!-- Shown after "resend messages" menuitem chosen -->
|
||||
<plurals name="resent_msgs_fmt">
|
||||
<item quantity="one">One message sent</item>
|
||||
|
@ -2571,8 +2603,7 @@
|
|||
<string name="confirm_clear_chat">Are you sure you want to delete
|
||||
all chat history for this game?\n\n(This action cannot be
|
||||
undone.)</string>
|
||||
<!-- EXPERIMENTAL: Shown as toast when user chooses "Copy to
|
||||
clipboard" for invitation -->
|
||||
|
||||
<string name="invite_copied">Invitation ready to paste</string>
|
||||
<!-- EXPERIMENTAL: "label" for invite on clipboard. If it's shown
|
||||
it's by some Android utility -->
|
||||
|
@ -2582,4 +2613,19 @@
|
|||
<string name="not_again_clip_expl_fmt">The \"%1$s\" option copies an
|
||||
invitation URL to the clipboard. Paste it into the app of your
|
||||
choice and send it to your friend.</string>
|
||||
|
||||
<string name="confirm_clear_chat">Are you sure you want to delete
|
||||
all chat history for this game?\n\n(This action cannot be
|
||||
undone.)</string>
|
||||
|
||||
<string name="rel_invite_title">Relay invite title</string>
|
||||
<string name="fetching_from_relay">Fetching games from relay</string>
|
||||
<string name="processing_games">Processing games</string>
|
||||
|
||||
<string name="list_item_select">Select</string>
|
||||
<string name="list_item_deselect">De-select</string>
|
||||
|
||||
<string name="not_again_dfltname_fmt">You are using the default
|
||||
player name \"%1$s\". Would you like to personalize with your own
|
||||
name before you create this game?</string>
|
||||
</resources>
|
||||
|
|
|
@ -231,11 +231,22 @@
|
|||
android:summary="@string/skip_confirm_turn_summary"
|
||||
android:defaultValue="false"
|
||||
/>
|
||||
<CheckBoxPreference android:key="@string/key_disable_nag"
|
||||
android:title="@string/disable_nag_title"
|
||||
android:summary="@string/disable_nag_summary"
|
||||
android:defaultValue="false"
|
||||
/>
|
||||
|
||||
<PreferenceScreen android:title="@string/disable_nags_title"
|
||||
>
|
||||
|
||||
<CheckBoxPreference android:key="@string/key_disable_nag"
|
||||
android:title="@string/disable_nag_title"
|
||||
android:summary="@string/disable_nag_summary"
|
||||
android:defaultValue="false"
|
||||
/>
|
||||
<CheckBoxPreference android:key="@string/key_disable_nag_solo"
|
||||
android:title="@string/disable_nag_solo_title"
|
||||
android:summary="@string/disable_nag_summary"
|
||||
android:defaultValue="true"
|
||||
/>
|
||||
</PreferenceScreen>
|
||||
|
||||
<CheckBoxPreference android:key="@string/key_default_loc"
|
||||
android:title="@string/default_loc"
|
||||
android:summary="@string/default_loc_summary"
|
||||
|
@ -394,6 +405,11 @@
|
|||
android:defaultValue="10998"
|
||||
android:numeric="decimal"
|
||||
/>
|
||||
<CheckBoxPreference android:key="@string/key_enable_relay_toself"
|
||||
android:title="@string/enable_relay_toself_title"
|
||||
android:summary="@string/enable_relay_toself_summary"
|
||||
android:defaultValue="false"
|
||||
/>
|
||||
</PreferenceScreen>
|
||||
|
||||
<PreferenceScreen android:title="@string/pref_group_l10n_title"
|
||||
|
@ -454,5 +470,9 @@
|
|||
android:summary="@string/git_rev"
|
||||
android:enabled="false"
|
||||
/>
|
||||
<org.eehouse.android.xw4.XWDevIDPreference
|
||||
android:title="@string/devid_title"
|
||||
android:enabled="false"
|
||||
/>
|
||||
</PreferenceScreen>
|
||||
</PreferenceScreen>
|
||||
|
|
|
@ -2371,9 +2371,6 @@ fois. Ouvrez à nouveau la partie pour réessayer.</string>
|
|||
<!--<string name="dft_sms_name_fmt">SMS Game %1$X</string> -->
|
||||
<string name="dft_sms_name_fmt">Partie %1$X par SMS</string>
|
||||
<!-- -->
|
||||
<!--<string name="new_sms_title">New game via SMS</string>-->
|
||||
<string name="new_sms_title">Nouvelle partie par SMS</string>
|
||||
<!-- -->
|
||||
<!--<string name="new_name_body_fmt">%1$s has invited you to play</string>-->
|
||||
<string name="new_name_body_fmt">%1$s vous a invité à jouer</string>
|
||||
<!-- -->
|
||||
|
@ -2411,7 +2408,7 @@ inviter, ou le bouton + pour saisir des numéros directement.</string>
|
|||
<!-- -->
|
||||
<!--<string name="confirm_clear">Are you sure you want to delete the
|
||||
checked phone number[s]?</string>-->
|
||||
<string name="confirm_clear">Êtes-vous sûr de vouloir effacer les numéros
|
||||
<string name="confirm_clear_sms">Êtes-vous sûr de vouloir effacer les numéros
|
||||
de téléphone cochés ?</string>
|
||||
<!-- -->
|
||||
<!--<string name="connect_label_sms">Connection (via SMS/text)</string>-->
|
||||
|
|
|
@ -1586,7 +1586,7 @@
|
|||
<!-- -->
|
||||
<string name="dft_sms_name_fmt">Jogo SMS %X</string>
|
||||
<!-- -->
|
||||
<string name="new_sms_title">Novo jogo por SMS</string>
|
||||
<string name="invite_notice_title">Novo jogo</string>
|
||||
<!-- -->
|
||||
<string name="new_name_body_fmt">%1$s te convidou para jogar</string>
|
||||
<!-- -->
|
||||
|
@ -1606,8 +1606,6 @@
|
|||
<!-- -->
|
||||
<string name="get_sms_number">Entre o número telefônico:</string>
|
||||
<!-- -->
|
||||
<!-- -->
|
||||
<!-- -->
|
||||
<string name="connect_label_sms">Conexão (por SMS/texto)</string>
|
||||
<!-- -->
|
||||
<string name="phone_label">Número(s) conectado(s):</string>
|
||||
|
|
|
@ -1243,7 +1243,7 @@
|
|||
<!-- -->
|
||||
<string name="invite_success">XLATE ME: Invitation received.</string>
|
||||
<!-- -->
|
||||
<string name="confirm_clear">XLATE ME: Are you sure you want to delete the
|
||||
<string name="confirm_clear_sms">XLATE ME: Are you sure you want to delete the
|
||||
checked phone number[s]?</string>
|
||||
<!-- -->
|
||||
<string name="get_sms_number">XLATE ME: Enter phone number:</string>
|
||||
|
@ -1267,8 +1267,6 @@
|
|||
<!-- -->
|
||||
<string name="new_name_body_fmt">XLATE ME: %1$s has invited you to play</string>
|
||||
<!-- -->
|
||||
<string name="new_sms_title">XLATE ME: New game via SMS</string>
|
||||
<!-- -->
|
||||
<string name="dft_sms_name_fmt">XLATE ME: SMS Game %1$X</string>
|
||||
<!-- -->
|
||||
<string name="sms_disabled">XLATE ME: Playing via SMS is currently disabled.
|
||||
|
|
1
xwords4/android/XWords4/settings.gradle
Normal file
1
xwords4/android/XWords4/settings.gradle
Normal file
|
@ -0,0 +1 @@
|
|||
include ':app'
|
|
@ -54,15 +54,15 @@ public class BTInviteDelegate extends InviteDelegate {
|
|||
private BTDevsAdapter m_adapter;
|
||||
|
||||
public static void launchForResult( Activity activity, int nMissing,
|
||||
int requestCode )
|
||||
RequestCode requestCode )
|
||||
{
|
||||
Assert.assertTrue( 0 < nMissing ); // don't call if nMissing == 0
|
||||
Intent intent = new Intent( activity, BTInviteActivity.class );
|
||||
intent.putExtra( INTENT_KEY_NMISSING, nMissing );
|
||||
activity.startActivityForResult( intent, requestCode );
|
||||
activity.startActivityForResult( intent, requestCode.ordinal() );
|
||||
}
|
||||
|
||||
protected BTInviteDelegate( ListDelegator delegator, Bundle savedInstanceState )
|
||||
protected BTInviteDelegate( Delegator delegator, Bundle savedInstanceState )
|
||||
{
|
||||
super( delegator, savedInstanceState, R.layout.btinviter );
|
||||
m_activity = delegator.getActivity();
|
||||
|
|
|
@ -42,6 +42,7 @@ import java.util.Iterator;
|
|||
import java.util.LinkedList;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -51,16 +52,21 @@ import org.eehouse.android.xw4.MultiService.MultiEvent;
|
|||
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
|
||||
import org.eehouse.android.xw4.jni.CommsAddrRec;
|
||||
import org.eehouse.android.xw4.jni.LastMoveInfo;
|
||||
import org.eehouse.android.xw4.jni.XwJNI;
|
||||
import org.eehouse.android.xw4.loc.LocUtils;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
public class BTService extends XWService {
|
||||
private static final String BOGUS_MARSHMALLOW_ADDR = "02:00:00:00:00:00";
|
||||
|
||||
private static final long RESEND_TIMEOUT = 5; // seconds
|
||||
private static final int MAX_SEND_FAIL = 3;
|
||||
|
||||
private static final int BT_PROTO = 1; // using jsons instead of lots of fields
|
||||
private static final int BT_PROTO_ORIG = 0;
|
||||
private static final int BT_PROTO_JSONS = 1; // using jsons instead of lots of fields
|
||||
private static final int BT_PROTO_NLI = 2; // using binary/common form of NLI
|
||||
private static final int BT_PROTO = BT_PROTO_JSONS; // change in a release or two
|
||||
|
||||
private enum BTAction { _NONE,
|
||||
SCAN,
|
||||
|
@ -105,6 +111,7 @@ public class BTService extends XWService {
|
|||
MESG_DECL,
|
||||
MESG_GAMEGONE,
|
||||
REMOVE_FOR,
|
||||
INVITE_DUP_INVITE,
|
||||
};
|
||||
|
||||
private class BTQueueElem {
|
||||
|
@ -134,22 +141,30 @@ public class BTService extends XWService {
|
|||
Assert.assertTrue( null != btAddr && 0 < btAddr.length() );
|
||||
m_msg = buf; m_btAddr = btAddr;
|
||||
m_gameID = gameID;
|
||||
checkAddr();
|
||||
}
|
||||
public BTQueueElem( BTCmd cmd, String btAddr, int gameID ) {
|
||||
this( cmd );
|
||||
Assert.assertTrue( null != btAddr && 0 < btAddr.length() );
|
||||
m_btAddr = btAddr;
|
||||
m_gameID = gameID;
|
||||
checkAddr();
|
||||
}
|
||||
|
||||
public BTQueueElem( BTCmd cmd, NetLaunchInfo nli, String btAddr ) {
|
||||
this( cmd );
|
||||
m_nli = nli;
|
||||
m_btAddr = btAddr;
|
||||
checkAddr();
|
||||
}
|
||||
|
||||
public int incrFailCount() { return ++m_failCount; }
|
||||
public boolean failCountExceeded() { return m_failCount >= MAX_SEND_FAIL; }
|
||||
|
||||
private void checkAddr()
|
||||
{
|
||||
Assert.assertFalse( BOGUS_MARSHMALLOW_ADDR.equals( m_btAddr ) );
|
||||
}
|
||||
}
|
||||
|
||||
private BluetoothAdapter m_adapter;
|
||||
|
@ -276,6 +291,7 @@ public class BTService extends XWService {
|
|||
public static void inviteRemote( Context context, String btAddr,
|
||||
NetLaunchInfo nli )
|
||||
{
|
||||
Assert.assertTrue( null != btAddr && 0 < btAddr.length() );
|
||||
Intent intent = getIntentTo( context, BTAction.INVITE );
|
||||
String nliData = nli.toString();
|
||||
intent.putExtra( GAMEDATA_KEY, nliData );
|
||||
|
@ -298,18 +314,23 @@ public class BTService extends XWService {
|
|||
}
|
||||
|
||||
public static int enqueueFor( Context context, byte[] buf,
|
||||
String targetAddr, int gameID )
|
||||
CommsAddrRec targetAddr, int gameID )
|
||||
{
|
||||
int nSent = -1;
|
||||
if ( null != targetAddr && 0 < targetAddr.length() ) {
|
||||
Assert.assertNotNull( targetAddr );
|
||||
String btAddr = getSafeAddr( targetAddr );
|
||||
if ( null != btAddr && 0 < btAddr.length() ) {
|
||||
Intent intent = getIntentTo( context, BTAction.SEND );
|
||||
intent.putExtra( MSG_KEY, buf );
|
||||
intent.putExtra( ADDR_KEY, targetAddr );
|
||||
intent.putExtra( ADDR_KEY, btAddr );
|
||||
intent.putExtra( GAMEID_KEY, gameID );
|
||||
context.startService( intent );
|
||||
nSent = buf.length;
|
||||
} else {
|
||||
DbgUtils.logf( "BTService.enqueueFor(): targetAddr is null" );
|
||||
}
|
||||
|
||||
if ( -1 == nSent ) {
|
||||
DbgUtils.logf( "BTService.enqueueFor(): can't send to %s",
|
||||
targetAddr.bt_hostName );
|
||||
}
|
||||
return nSent;
|
||||
}
|
||||
|
@ -373,12 +394,6 @@ public class BTService extends XWService {
|
|||
String jsonData = intent.getStringExtra( GAMEDATA_KEY );
|
||||
NetLaunchInfo nli = new NetLaunchInfo( this, jsonData );
|
||||
DbgUtils.logf( "onStartCommand: nli: %s", nli.toString() );
|
||||
// int gameID = intent.getIntExtra( GAMEID_KEY, -1 );
|
||||
// String btAddr = intent.getStringExtra( ADDR_KEY );
|
||||
// String gameName = intent.getStringExtra( GAMENAME_KEY );
|
||||
// int lang = intent.getIntExtra( LANG_KEY, -1 );
|
||||
// String dict = intent.getStringExtra( DICT_KEY );
|
||||
// int nPlayersT = intent.getIntExtra( NTO_KEY, -1 );
|
||||
String btAddr = intent.getStringExtra( ADDR_KEY );
|
||||
m_sender.add( new BTQueueElem( BTCmd.INVITE, nli, btAddr ) );
|
||||
break;
|
||||
|
@ -457,42 +472,39 @@ public class BTService extends XWService {
|
|||
}
|
||||
|
||||
while ( null != m_serverSocket && m_adapter.isEnabled() ) {
|
||||
|
||||
BluetoothSocket socket = null;
|
||||
DataInputStream inStream = null;
|
||||
int nRead = 0;
|
||||
try {
|
||||
socket = m_serverSocket.accept(); // blocks
|
||||
BluetoothSocket socket = m_serverSocket.accept(); // blocks
|
||||
addAddr( socket );
|
||||
inStream = new DataInputStream( socket.getInputStream() );
|
||||
DataInputStream inStream =
|
||||
new DataInputStream( socket.getInputStream() );
|
||||
|
||||
byte proto = inStream.readByte();
|
||||
if ( proto != BT_PROTO ) {
|
||||
DataOutputStream os = new DataOutputStream( socket.getOutputStream() );
|
||||
os.writeByte( BTCmd.BAD_PROTO.ordinal() );
|
||||
os.flush();
|
||||
socket.close();
|
||||
|
||||
sendBadProto( socket );
|
||||
} else {
|
||||
byte msg = inStream.readByte();
|
||||
BTCmd cmd = BTCmd.values()[msg];
|
||||
BTCmd cmd = BTCmd.values()[inStream.readByte()];
|
||||
if ( protoOK( proto, cmd ) ) {
|
||||
switch( cmd ) {
|
||||
case PING:
|
||||
receivePing( socket );
|
||||
break;
|
||||
case INVITE:
|
||||
receiveInvitation( inStream, socket );
|
||||
receiveInvitation( proto, inStream, socket );
|
||||
break;
|
||||
case MESG_SEND:
|
||||
receiveMessage( inStream, socket );
|
||||
break;
|
||||
|
||||
default:
|
||||
DbgUtils.logf( "unexpected msg %d", msg );
|
||||
DbgUtils.logf( "unexpected msg %s", cmd.toString());
|
||||
break;
|
||||
}
|
||||
updateStatusIn( true );
|
||||
} else {
|
||||
DataOutputStream os =
|
||||
new DataOutputStream( socket.getOutputStream() );
|
||||
os.writeByte( BTCmd.BAD_PROTO.ordinal() );
|
||||
os.flush();
|
||||
socket.close();
|
||||
|
||||
sendBadProto( socket );
|
||||
}
|
||||
} catch ( IOException ioe ) {
|
||||
DbgUtils.logf( "trying again..." );
|
||||
|
@ -524,6 +536,12 @@ public class BTService extends XWService {
|
|||
interrupt();
|
||||
}
|
||||
|
||||
private boolean protoOK( byte proto, BTCmd cmd )
|
||||
{
|
||||
boolean ok = proto == BT_PROTO_NLI || proto == BT_PROTO_JSONS;
|
||||
return ok;
|
||||
}
|
||||
|
||||
private void receivePing( BluetoothSocket socket ) throws IOException
|
||||
{
|
||||
DataInputStream inStream = new DataInputStream( socket.getInputStream() );
|
||||
|
@ -539,13 +557,21 @@ public class BTService extends XWService {
|
|||
updateStatusOut( true );
|
||||
}
|
||||
|
||||
private void receiveInvitation( DataInputStream is,
|
||||
private void receiveInvitation( byte proto, DataInputStream is,
|
||||
BluetoothSocket socket )
|
||||
throws IOException
|
||||
{
|
||||
BTCmd result;
|
||||
String asJson = is.readUTF();
|
||||
NetLaunchInfo nli = new NetLaunchInfo( BTService.this, asJson );
|
||||
NetLaunchInfo nli;
|
||||
if ( BT_PROTO_JSONS == proto ) {
|
||||
String asJson = is.readUTF();
|
||||
nli = new NetLaunchInfo( BTService.this, asJson );
|
||||
} else {
|
||||
short len = is.readShort();
|
||||
byte[] nliData = new byte[len];
|
||||
is.read( nliData );
|
||||
nli = XwJNI.nliFromStream( nliData );
|
||||
}
|
||||
|
||||
BluetoothDevice host = socket.getRemoteDevice();
|
||||
addAddr( host );
|
||||
|
@ -644,6 +670,32 @@ public class BTService extends XWService {
|
|||
return m_addrs.contains( btAddr );
|
||||
}
|
||||
|
||||
private static Map<String, String> s_namesToAddrs;
|
||||
private static String getSafeAddr( CommsAddrRec addr )
|
||||
{
|
||||
String btAddr = addr.bt_btAddr;
|
||||
if ( BOGUS_MARSHMALLOW_ADDR.equals( btAddr ) ) {
|
||||
String btName = addr.bt_hostName;
|
||||
if ( null == s_namesToAddrs ) {
|
||||
s_namesToAddrs = new HashMap<String, String>();
|
||||
}
|
||||
if ( ! s_namesToAddrs.containsKey( btName ) ) {
|
||||
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
||||
if ( null != adapter ) {
|
||||
Set<BluetoothDevice> devs = adapter.getBondedDevices();
|
||||
Iterator<BluetoothDevice> iter = devs.iterator();
|
||||
while ( iter.hasNext() ) {
|
||||
BluetoothDevice dev = iter.next();
|
||||
s_namesToAddrs.put( dev.getName(), dev.getAddress() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
btAddr = s_namesToAddrs.get( btName );
|
||||
}
|
||||
return btAddr;
|
||||
}
|
||||
|
||||
private void clearDevs( String[] btAddrs )
|
||||
{
|
||||
if ( null != btAddrs ) {
|
||||
|
@ -802,7 +854,13 @@ public class BTService extends XWService {
|
|||
BTCmd reply = null;
|
||||
DataOutputStream outStream = connect( socket, BTCmd.INVITE );
|
||||
if ( null != outStream ) {
|
||||
outStream.writeUTF( elem.m_nli.toString() );
|
||||
if ( BT_PROTO == BT_PROTO_JSONS ) {
|
||||
outStream.writeUTF( elem.m_nli.toString() );
|
||||
} else {
|
||||
byte[] nliData = XwJNI.nliToStream( elem.m_nli );
|
||||
outStream.writeShort( nliData.length );
|
||||
outStream.write( nliData, 0, nliData.length );
|
||||
}
|
||||
DbgUtils.logf( "<eeh>sending invite for %d players", elem.m_nPlayersH );
|
||||
outStream.flush();
|
||||
|
||||
|
@ -1060,16 +1118,20 @@ public class BTService extends XWService {
|
|||
String btAddr )
|
||||
{
|
||||
BTCmd result;
|
||||
if ( DictLangCache.haveDict( this, nli.lang, nli.dict ) ) {
|
||||
result = makeGame( nli, btName, btAddr );
|
||||
if ( checkNotDupe( nli ) ) {
|
||||
if ( DictLangCache.haveDict( this, nli.lang, nli.dict ) ) {
|
||||
result = makeGame( nli, btName, btAddr );
|
||||
} else {
|
||||
Intent intent = MultiService
|
||||
.makeMissingDictIntent( this, nli,
|
||||
DictFetchOwner.OWNER_BT );
|
||||
// NetLaunchInfo.putExtras( intent, gameID, btName, btAddr );
|
||||
MultiService.postMissingDictNotification( this, intent,
|
||||
nli.gameID() );
|
||||
result = BTCmd.INVITE_ACCPT; // ???
|
||||
}
|
||||
} else {
|
||||
Intent intent = MultiService
|
||||
.makeMissingDictIntent( this, nli,
|
||||
DictFetchOwner.OWNER_BT );
|
||||
// NetLaunchInfo.putExtras( intent, gameID, btName, btAddr );
|
||||
MultiService.postMissingDictNotification( this, intent,
|
||||
nli.gameID() );
|
||||
result = BTCmd.INVITE_ACCPT; // ???
|
||||
result = BTCmd.INVITE_DUP_INVITE; // dupe of rematch
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -1081,7 +1143,8 @@ public class BTService extends XWService {
|
|||
long[] rowids = DBUtils.getRowIDsFor( BTService.this, nli.gameID() );
|
||||
if ( null == rowids || 0 == rowids.length ) {
|
||||
CommsAddrRec addr = nli.makeAddrRec( BTService.this );
|
||||
long rowid = GameUtils.makeNewMultiGame( BTService.this, nli, m_btMsgSink );
|
||||
long rowid = GameUtils.makeNewMultiGame( BTService.this, nli,
|
||||
m_btMsgSink, null );
|
||||
if ( DBUtils.ROWID_NOTFOUND == rowid ) {
|
||||
result = BTCmd.INVITE_FAILED;
|
||||
} else {
|
||||
|
@ -1092,7 +1155,10 @@ public class BTService extends XWService {
|
|||
String body = LocUtils.getString( BTService.this,
|
||||
R.string.new_bt_body_fmt,
|
||||
sender );
|
||||
postNotification( nli.gameID(), R.string.new_bt_title, body, rowid );
|
||||
|
||||
GameUtils.postInvitedNotification( this, nli.gameID(), body,
|
||||
rowid );
|
||||
|
||||
sendResult( MultiEvent.BT_GAME_CREATED, rowid );
|
||||
}
|
||||
} else {
|
||||
|
@ -1137,14 +1203,6 @@ public class BTService extends XWService {
|
|||
sendResult( MultiEvent.BAD_PROTO_BT, socket.getRemoteDevice().getName() );
|
||||
}
|
||||
|
||||
private void postNotification( int gameID, int title, String body,
|
||||
long rowid )
|
||||
{
|
||||
Intent intent = GamesListDelegate.makeGameIDIntent( this, gameID );
|
||||
Utils.postNotification( this, intent, R.string.new_btmove_title,
|
||||
body, (int)rowid );
|
||||
}
|
||||
|
||||
private void updateStatusOut( boolean success )
|
||||
{
|
||||
ConnStatusHandler
|
||||
|
@ -1191,9 +1249,11 @@ public class BTService extends XWService {
|
|||
@Override
|
||||
public int sendViaBluetooth( byte[] buf, int gameID, CommsAddrRec addr )
|
||||
{
|
||||
String btAddr = getSafeAddr( addr );
|
||||
|
||||
Assert.assertTrue( addr.contains( CommsConnType.COMMS_CONN_BT ) );
|
||||
m_sender.add( new BTQueueElem( BTCmd.MESG_SEND, buf,
|
||||
addr.bt_btAddr, gameID ) );
|
||||
m_sender.add( new BTQueueElem( BTCmd.MESG_SEND, buf,
|
||||
btAddr, gameID ) );
|
||||
return buf.length;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,8 +23,9 @@ package org.eehouse.android.xw4;
|
|||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface.OnCancelListener;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.content.DialogInterface.OnDismissListener;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
|
@ -68,10 +69,6 @@ public class BoardDelegate extends DelegateBase
|
|||
|
||||
public static final String INTENT_KEY_CHAT = "chat";
|
||||
|
||||
private static final int CHAT_REQUEST = 1;
|
||||
private static final int BT_INVITE_RESULT = 2;
|
||||
private static final int SMS_INVITE_RESULT = 3;
|
||||
|
||||
private static final int SCREEN_ON_TIME = 10 * 60 * 1000; // 10 mins
|
||||
|
||||
private static final String DLG_TITLE = "DLG_TITLE";
|
||||
|
@ -236,11 +233,12 @@ public class BoardDelegate extends DelegateBase
|
|||
}
|
||||
};
|
||||
ab.setNegativeButton( R.string.button_retry, lstnr );
|
||||
} else if ( DlgID.GAME_OVER == dlgID && rematchSupported() ) {
|
||||
} else if ( DlgID.GAME_OVER == dlgID
|
||||
&& rematchSupported( true ) ) {
|
||||
lstnr = new OnClickListener() {
|
||||
public void onClick( DialogInterface dlg,
|
||||
int whichButton ) {
|
||||
doRematch();
|
||||
doRematchIf();
|
||||
}
|
||||
};
|
||||
ab.setNegativeButton( R.string.button_rematch, lstnr );
|
||||
|
@ -450,7 +448,7 @@ public class BoardDelegate extends DelegateBase
|
|||
dialog = ab.setTitle( "foo" )
|
||||
.setMessage( "" )
|
||||
.setPositiveButton( "", lstnr )
|
||||
.setNegativeButton( R.string.button_close_game, lstnr2 )
|
||||
.setNegativeButton( R.string.button_wait, lstnr2 )
|
||||
.setOnCancelListener( new OnCancelListener() {
|
||||
public void onCancel( DialogInterface dialog ) {
|
||||
finish();
|
||||
|
@ -641,9 +639,11 @@ public class BoardDelegate extends DelegateBase
|
|||
}
|
||||
}
|
||||
|
||||
protected void onActivityResult( int requestCode, int resultCode, Intent data )
|
||||
@Override
|
||||
protected void onActivityResult( RequestCode requestCode, int resultCode, Intent data )
|
||||
{
|
||||
if ( Activity.RESULT_CANCELED != resultCode ) {
|
||||
InviteMeans missingMeans = null;
|
||||
switch ( requestCode ) {
|
||||
case CHAT_REQUEST:
|
||||
if ( BuildConstants.CHAT_SUPPORTED ) {
|
||||
|
@ -655,14 +655,22 @@ public class BoardDelegate extends DelegateBase
|
|||
}
|
||||
break;
|
||||
case BT_INVITE_RESULT:
|
||||
missingMeans = InviteMeans.BLUETOOTH;
|
||||
break;
|
||||
case SMS_INVITE_RESULT:
|
||||
// onActivityResult is called immediately *before*
|
||||
// onResume -- meaning m_gi etc are still null.
|
||||
missingMeans = InviteMeans.SMS;
|
||||
break;
|
||||
case RELAY_INVITE_RESULT:
|
||||
missingMeans = InviteMeans.RELAY;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( null != missingMeans ) {
|
||||
// onActivityResult is called immediately *before* onResume --
|
||||
// meaning m_gi etc are still null.
|
||||
m_missingDevs = data.getStringArrayExtra( InviteDelegate.DEVS );
|
||||
m_missingCounts = data.getIntArrayExtra( InviteDelegate.COUNTS );
|
||||
m_missingMeans = (BT_INVITE_RESULT == requestCode)
|
||||
? InviteMeans.BLUETOOTH : InviteMeans.SMS;
|
||||
break;
|
||||
m_missingMeans = missingMeans;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -729,6 +737,7 @@ public class BoardDelegate extends DelegateBase
|
|||
boolean inTrade = false;
|
||||
MenuItem item;
|
||||
int strId;
|
||||
boolean enable;
|
||||
|
||||
if ( null != m_gsi ) {
|
||||
inTrade = m_gsi.inTrade;
|
||||
|
@ -773,10 +782,10 @@ public class BoardDelegate extends DelegateBase
|
|||
Utils.setItemVisible( menu, R.id.board_menu_game_resign, !inTrade );
|
||||
|
||||
if ( !inTrade ) {
|
||||
boolean enabled = null == m_gsi || m_gsi.curTurnSelected;
|
||||
enable = null == m_gsi || m_gsi.curTurnSelected;
|
||||
item = menu.findItem( R.id.board_menu_done );
|
||||
item.setVisible( enabled );
|
||||
if ( enabled ) {
|
||||
item.setVisible( enable );
|
||||
if ( enable ) {
|
||||
if ( 0 >= m_view.curPending() ) {
|
||||
strId = R.string.board_menu_pass;
|
||||
} else {
|
||||
|
@ -791,7 +800,10 @@ public class BoardDelegate extends DelegateBase
|
|||
}
|
||||
}
|
||||
|
||||
boolean enable = null != m_gi
|
||||
enable = m_gameOver && rematchSupported( false );
|
||||
Utils.setItemVisible( menu, R.id.board_menu_rematch, enable );
|
||||
|
||||
enable = null != m_gi
|
||||
&& DeviceRole.SERVER_STANDALONE != m_gi.serverRole;
|
||||
Utils.setItemVisible( menu, R.id.gamel_menu_checkmoves, enable );
|
||||
Utils.setItemVisible( menu, R.id.board_menu_game_resend,
|
||||
|
@ -828,6 +840,10 @@ public class BoardDelegate extends DelegateBase
|
|||
}
|
||||
break;
|
||||
|
||||
case R.id.board_menu_rematch:
|
||||
doRematchIf();
|
||||
break;
|
||||
|
||||
case R.id.board_menu_trade_commit:
|
||||
cmd = JNICmd.CMD_COMMIT;
|
||||
break;
|
||||
|
@ -1039,11 +1055,15 @@ public class BoardDelegate extends DelegateBase
|
|||
break;
|
||||
case BLUETOOTH:
|
||||
BTInviteDelegate.launchForResult( m_activity, m_nMissing,
|
||||
BT_INVITE_RESULT );
|
||||
RequestCode.BT_INVITE_RESULT );
|
||||
break;
|
||||
case SMS:
|
||||
SMSInviteDelegate.launchForResult( m_activity, m_nMissing,
|
||||
SMS_INVITE_RESULT );
|
||||
RequestCode.SMS_INVITE_RESULT );
|
||||
break;
|
||||
case RELAY:
|
||||
RelayInviteDelegate.launchForResult( m_activity, m_nMissing,
|
||||
RequestCode.RELAY_INVITE_RESULT );
|
||||
break;
|
||||
case EMAIL:
|
||||
case CLIPBOARD:
|
||||
|
@ -1661,8 +1681,8 @@ public class BoardDelegate extends DelegateBase
|
|||
m_nMissing = 0;
|
||||
post( new Runnable() {
|
||||
public void run() {
|
||||
showNotAgainDlgThen( R.string.not_again_turnchanged,
|
||||
R.string.key_notagain_turnchanged );
|
||||
showNotAgainDlg( R.string.not_again_turnchanged,
|
||||
R.string.key_notagain_turnchanged );
|
||||
}
|
||||
} );
|
||||
m_jniThread.handle( JNICmd. CMD_ZOOM, -8 );
|
||||
|
@ -2035,6 +2055,8 @@ public class BoardDelegate extends DelegateBase
|
|||
m_view.startHandling( m_activity, m_jniThread, m_jniGamePtr, m_gi,
|
||||
m_connTypes );
|
||||
if ( null != m_xport ) {
|
||||
// informMissing should have been called by now
|
||||
Assert.assertNotNull( m_connTypes );
|
||||
m_xport.setReceiver( m_jniThread, m_handler );
|
||||
}
|
||||
m_jniThread.handle( JNICmd.CMD_START );
|
||||
|
@ -2284,7 +2306,7 @@ public class BoardDelegate extends DelegateBase
|
|||
if ( BuildConstants.CHAT_SUPPORTED ) {
|
||||
Intent intent = new Intent( m_activity, ChatActivity.class );
|
||||
intent.putExtra( GameUtils.INTENT_KEY_ROWID, m_rowid );
|
||||
startActivityForResult( intent, CHAT_REQUEST );
|
||||
startActivityForResult( intent, RequestCode.CHAT_REQUEST );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2348,50 +2370,56 @@ public class BoardDelegate extends DelegateBase
|
|||
|
||||
private void tryInvites()
|
||||
{
|
||||
if ( XWApp.BTSUPPORTED || XWApp.SMSSUPPORTED ) {
|
||||
// test if summary knows of rematch pending first
|
||||
if ( 0 < m_nMissing && m_summary.hasRematchInfo() ) {
|
||||
tryRematchInvites();
|
||||
} else if ( null != m_missingDevs ) {
|
||||
Assert.assertNotNull( m_missingMeans );
|
||||
String gameName = GameUtils.getName( m_activity, m_rowid );
|
||||
m_invitesPending = m_missingDevs.length;
|
||||
for ( int ii = 0; ii < m_missingDevs.length; ++ii ) {
|
||||
String dev = m_missingDevs[ii];
|
||||
int nPlayers = m_missingCounts[ii];
|
||||
Assert.assertTrue( 0 <= m_nGuestDevs );
|
||||
int forceChannel = ii + m_nGuestDevs + 1;
|
||||
NetLaunchInfo nli = new NetLaunchInfo( m_summary, m_gi,
|
||||
nPlayers, forceChannel );
|
||||
if ( !m_relayConnected ) {
|
||||
nli.removeAddress( CommsConnType.COMMS_CONN_RELAY );
|
||||
}
|
||||
|
||||
switch ( m_missingMeans ) {
|
||||
case BLUETOOTH:
|
||||
if ( ! m_progressShown ) {
|
||||
m_progressShown = true;
|
||||
String progMsg = BTService.nameForAddr( dev );
|
||||
progMsg = getString( R.string.invite_progress_fmt, progMsg );
|
||||
startProgress( R.string.invite_progress_title, progMsg,
|
||||
new OnCancelListener() {
|
||||
public void onCancel( DialogInterface dlg )
|
||||
{
|
||||
m_progressShown = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
BTService.inviteRemote( m_activity, dev, nli );
|
||||
break;
|
||||
case SMS:
|
||||
SMSService.inviteRemote( m_activity, dev, nli );
|
||||
break;
|
||||
}
|
||||
if ( 0 < m_nMissing && m_summary.hasRematchInfo() ) {
|
||||
tryRematchInvites();
|
||||
} else if ( null != m_missingDevs ) {
|
||||
Assert.assertNotNull( m_missingMeans );
|
||||
String gameName = GameUtils.getName( m_activity, m_rowid );
|
||||
m_invitesPending = m_missingDevs.length;
|
||||
for ( int ii = 0; ii < m_missingDevs.length; ++ii ) {
|
||||
String dev = m_missingDevs[ii];
|
||||
int nPlayers = m_missingCounts[ii];
|
||||
Assert.assertTrue( 0 <= m_nGuestDevs );
|
||||
int forceChannel = ii + m_nGuestDevs + 1;
|
||||
NetLaunchInfo nli = new NetLaunchInfo( m_summary, m_gi,
|
||||
nPlayers, forceChannel );
|
||||
if ( !m_relayConnected ) {
|
||||
nli.removeAddress( CommsConnType.COMMS_CONN_RELAY );
|
||||
}
|
||||
|
||||
switch ( m_missingMeans ) {
|
||||
case BLUETOOTH:
|
||||
if ( ! m_progressShown ) {
|
||||
m_progressShown = true;
|
||||
String progMsg = BTService.nameForAddr( dev );
|
||||
progMsg = getString( R.string.invite_progress_fmt, progMsg );
|
||||
startProgress( R.string.invite_progress_title, progMsg,
|
||||
new OnCancelListener() {
|
||||
public void onCancel( DialogInterface dlg )
|
||||
{
|
||||
m_progressShown = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
BTService.inviteRemote( m_activity, dev, nli );
|
||||
break;
|
||||
case SMS:
|
||||
SMSService.inviteRemote( m_activity, dev, nli );
|
||||
break;
|
||||
case RELAY:
|
||||
try {
|
||||
int destDevID = Integer.parseInt( dev ); // failing
|
||||
RelayService.inviteRemote( m_activity, destDevID,
|
||||
null, nli );
|
||||
} catch (NumberFormatException nfi) {
|
||||
DbgUtils.loge( nfi );
|
||||
}
|
||||
break;
|
||||
}
|
||||
m_missingDevs = null;
|
||||
m_missingCounts = null;
|
||||
m_missingMeans = null;
|
||||
}
|
||||
m_missingDevs = null;
|
||||
m_missingCounts = null;
|
||||
m_missingMeans = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2497,29 +2525,77 @@ public class BoardDelegate extends DelegateBase
|
|||
}
|
||||
|
||||
// For now, supported if standalone or either BT or SMS used for transport
|
||||
private boolean rematchSupported()
|
||||
private boolean rematchSupported( boolean showMulti )
|
||||
{
|
||||
return rematchSupported( showMulti ? m_activity : null,
|
||||
m_summary );
|
||||
}
|
||||
|
||||
public static boolean rematchSupported( Context context, long rowID )
|
||||
{
|
||||
GameSummary summary = DBUtils.getSummary( context, rowID, 1 );
|
||||
return null != summary && rematchSupported( null, summary );
|
||||
}
|
||||
|
||||
private static boolean rematchSupported( Context context,
|
||||
GameSummary summary )
|
||||
{
|
||||
boolean supported = false;
|
||||
if ( XWApp.REMATCH_SUPPORTED ) {
|
||||
supported = m_gi.serverRole == DeviceRole.SERVER_STANDALONE;
|
||||
if ( !supported && 2 == m_gi.nPlayers ) {
|
||||
supported = m_connTypes.contains( CommsConnType.COMMS_CONN_BT )
|
||||
|| m_connTypes.contains( CommsConnType.COMMS_CONN_SMS )
|
||||
|| m_connTypes.contains( CommsConnType.COMMS_CONN_RELAY );
|
||||
// standalone games are easy to rematch
|
||||
supported = summary.serverRole == DeviceRole.SERVER_STANDALONE;
|
||||
|
||||
if ( !supported ) {
|
||||
if ( 2 == summary.nPlayers ) {
|
||||
if ( !summary.anyMissing() ) {
|
||||
CommsConnTypeSet connTypes = summary.conTypes;
|
||||
supported = connTypes.contains( CommsConnType.COMMS_CONN_BT )
|
||||
|| connTypes.contains( CommsConnType.COMMS_CONN_SMS )
|
||||
|| connTypes.contains( CommsConnType.COMMS_CONN_RELAY );
|
||||
}
|
||||
} else if ( null != context ) {
|
||||
// show the button if people haven't dismissed the hint yet
|
||||
supported = ! XWPrefs
|
||||
.getPrefsBoolean( context,
|
||||
R.string.key_na_rematch_two_only,
|
||||
false );
|
||||
}
|
||||
}
|
||||
}
|
||||
return supported;
|
||||
}
|
||||
|
||||
private void doRematch()
|
||||
private void doRematchIf()
|
||||
{
|
||||
if ( doRematchIf( m_activity, this, m_rowid, m_summary, m_gi,
|
||||
m_jniGamePtr ) ) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean doRematchIf( Activity activity, DelegateBase dlgt,
|
||||
long rowid, GameSummary summary,
|
||||
CurGameInfo gi, int jniGamePtr )
|
||||
{
|
||||
boolean success = false;
|
||||
if ( XWApp.REMATCH_SUPPORTED ) {
|
||||
boolean doIt = true;
|
||||
String phone = null;
|
||||
String btAddr = null;
|
||||
String relayID = null;
|
||||
if ( m_gi.serverRole != DeviceRole.SERVER_STANDALONE ) {
|
||||
CommsAddrRec[] addrs = XwJNI.comms_getAddrs( m_jniGamePtr );
|
||||
for ( CommsAddrRec addr : addrs ) {
|
||||
if ( DeviceRole.SERVER_STANDALONE == gi.serverRole ) {
|
||||
// nothing to do??
|
||||
} else if ( 2 != gi.nPlayers ) {
|
||||
Assert.assertNotNull( dlgt );
|
||||
if ( null != dlgt ) {
|
||||
dlgt.showNotAgainDlg( R.string.not_again_rematch_two_only,
|
||||
R.string.key_na_rematch_two_only );
|
||||
}
|
||||
doIt = false;
|
||||
} else {
|
||||
CommsAddrRec[] addrs = XwJNI.comms_getAddrs( jniGamePtr );
|
||||
for ( int ii = 0; ii < addrs.length; ++ii ) {
|
||||
CommsAddrRec addr = addrs[ii];
|
||||
if ( addr.contains( CommsConnType.COMMS_CONN_BT ) ) {
|
||||
Assert.assertNull( btAddr );
|
||||
btAddr = addr.bt_btAddr;
|
||||
|
@ -2530,19 +2606,42 @@ public class BoardDelegate extends DelegateBase
|
|||
}
|
||||
if ( addr.contains( CommsConnType.COMMS_CONN_RELAY ) ) {
|
||||
Assert.assertNull( relayID );
|
||||
relayID = m_summary.relayID;
|
||||
relayID = XwJNI.comms_formatRelayID( jniGamePtr, ii );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Intent intent = GamesListDelegate
|
||||
.makeRematchIntent( m_activity, m_rowid, m_connTypes, btAddr,
|
||||
phone, relayID );
|
||||
if ( null != intent ) {
|
||||
startActivity( intent );
|
||||
finish();
|
||||
if ( doIt ) {
|
||||
CommsConnTypeSet connTypes = summary.conTypes;
|
||||
String newName = summary.getRematchName();
|
||||
Intent intent = GamesListDelegate
|
||||
.makeRematchIntent( activity, rowid, gi.dictName,
|
||||
gi.dictLang, connTypes, btAddr,
|
||||
phone, relayID, newName );
|
||||
if ( null != intent ) {
|
||||
activity.startActivity( intent );
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
public static void setupRematchFor( Activity activity, long rowID )
|
||||
{
|
||||
GameLock lock = new GameLock( rowID, false );
|
||||
if ( lock.tryLock() ) {
|
||||
GameSummary summary = DBUtils.getSummary( activity, lock );
|
||||
CurGameInfo gi = new CurGameInfo( activity );
|
||||
int gamePtr = GameUtils.loadMakeGame( activity, gi, lock );
|
||||
|
||||
doRematchIf( activity, null, rowID, summary, gi, gamePtr );
|
||||
|
||||
XwJNI.game_dispose( gamePtr );
|
||||
lock.unlock();
|
||||
} else {
|
||||
DbgUtils.logf( "setupRematchFor(): unable to lock game" );
|
||||
}
|
||||
}
|
||||
|
||||
private void tryRematchInvites()
|
||||
|
@ -2567,10 +2666,9 @@ public class BoardDelegate extends DelegateBase
|
|||
if ( null != value ) {
|
||||
BTService.inviteRemote( m_activity, value, nli );
|
||||
}
|
||||
|
||||
value = m_summary.getStringExtra( GameSummary.EXTRA_REMATCH_RELAY );
|
||||
if ( null != value ) {
|
||||
RelayService.inviteRemote( m_activity, value, nli );
|
||||
RelayService.inviteRemote( m_activity, 0, value, nli );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ public class CommsTransport implements TransportProcs,
|
|||
private SocketChannel m_socketChannel;
|
||||
private int m_jniGamePtr;
|
||||
private CommsAddrRec m_relayAddr;
|
||||
private String m_useHost;
|
||||
private JNIThread m_jniThread;
|
||||
private CommsThread m_thread;
|
||||
private TransportProcs.TPMsgHandler m_tpHandler;
|
||||
|
@ -86,7 +87,7 @@ public class CommsTransport implements TransportProcs,
|
|||
m_done = false;
|
||||
boolean failed = true;
|
||||
try {
|
||||
if ( Build.PRODUCT.contains("sdk") ) {
|
||||
if ( XWApp.onEmulator() ) {
|
||||
System.setProperty("java.net.preferIPv6Addresses", "false");
|
||||
}
|
||||
|
||||
|
@ -99,8 +100,7 @@ public class CommsTransport implements TransportProcs,
|
|||
DbgUtils.loge( ioe );
|
||||
} catch ( UnresolvedAddressException uae ) {
|
||||
DbgUtils.logf( "bad address: name: %s; port: %s; exception: %s",
|
||||
m_relayAddr.ip_relay_hostName,
|
||||
m_relayAddr.ip_relay_port,
|
||||
m_useHost, m_relayAddr.ip_relay_port,
|
||||
uae.toString() );
|
||||
}
|
||||
|
||||
|
@ -127,11 +127,11 @@ public class CommsTransport implements TransportProcs,
|
|||
try {
|
||||
m_socketChannel = SocketChannel.open();
|
||||
m_socketChannel.configureBlocking( false );
|
||||
DbgUtils.logf( "connecting to %s:%d",
|
||||
m_relayAddr.ip_relay_hostName,
|
||||
DbgUtils.logf( "connecting to %s:%d",
|
||||
m_useHost,
|
||||
m_relayAddr.ip_relay_port );
|
||||
InetSocketAddress isa = new
|
||||
InetSocketAddress(m_relayAddr.ip_relay_hostName,
|
||||
InetSocketAddress(m_useHost,
|
||||
m_relayAddr.ip_relay_port );
|
||||
m_socketChannel.connect( isa );
|
||||
} catch ( java.io.IOException ioe ) {
|
||||
|
@ -356,9 +356,11 @@ public class CommsTransport implements TransportProcs,
|
|||
|
||||
public int getFlags() { return COMMS_XPORT_FLAGS_NONE; }
|
||||
|
||||
public int transportSend( byte[] buf, CommsAddrRec addr,
|
||||
public int transportSend( byte[] buf, String msgNo, CommsAddrRec addr,
|
||||
CommsConnType conType, int gameID )
|
||||
{
|
||||
DbgUtils.logdf( "CommsTransport.transportSend(len=%d, typ=%s)",
|
||||
buf.length, conType.toString() );
|
||||
int nSent = -1;
|
||||
Assert.assertNotNull( addr );
|
||||
Assert.assertTrue( addr.contains( conType ) );
|
||||
|
@ -366,6 +368,7 @@ public class CommsTransport implements TransportProcs,
|
|||
if ( !XWApp.UDP_ENABLED && conType == CommsConnType.COMMS_CONN_RELAY
|
||||
&& null == m_relayAddr ) {
|
||||
m_relayAddr = new CommsAddrRec( addr );
|
||||
m_useHost = NetUtils.forceHost( m_relayAddr.ip_relay_hostName );
|
||||
}
|
||||
|
||||
if ( !XWApp.UDP_ENABLED && conType == CommsConnType.COMMS_CONN_RELAY ) {
|
||||
|
@ -385,7 +388,7 @@ public class CommsTransport implements TransportProcs,
|
|||
// Keep this while debugging why the resend_all that gets
|
||||
// fired on reconnect doesn't unstall a game but a manual
|
||||
// resend does.
|
||||
DbgUtils.logf( "transportSend(%d)=>%d", buf.length, nSent );
|
||||
DbgUtils.logdf( "transportSend(%d)=>%d", buf.length, nSent );
|
||||
return nSent;
|
||||
}
|
||||
|
||||
|
@ -426,7 +429,7 @@ public class CommsTransport implements TransportProcs,
|
|||
m_tpHandler.tpmRelayErrorProc( relayErr );
|
||||
}
|
||||
|
||||
public boolean relayNoConnProc( byte[] buf, String relayID )
|
||||
public boolean relayNoConnProc( byte[] buf, String msgNo, String relayID )
|
||||
{
|
||||
Assert.fail();
|
||||
return false;
|
||||
|
@ -447,7 +450,7 @@ public class CommsTransport implements TransportProcs,
|
|||
gameID, buf );
|
||||
break;
|
||||
case COMMS_CONN_BT:
|
||||
nSent = BTService.enqueueFor( context, buf, addr.bt_btAddr, gameID );
|
||||
nSent = BTService.enqueueFor( context, buf, addr, gameID );
|
||||
break;
|
||||
default:
|
||||
Assert.fail();
|
||||
|
|
|
@ -190,8 +190,14 @@ public class ConnStatusHandler {
|
|||
R.string.connstat_net_fmt,
|
||||
connTypes.toString( context )));
|
||||
for ( CommsConnType typ : connTypes.getTypes() ) {
|
||||
sb.append( String.format( "\n\n*** %s ***\n",
|
||||
typ.longName( context ) ) );
|
||||
String did = "";
|
||||
if ( BuildConfig.DEBUG
|
||||
&& CommsConnType.COMMS_CONN_RELAY == typ ) {
|
||||
did = String.format( "(DevID: %d) ",
|
||||
DevID.getRelayDevIDInt(context) );
|
||||
}
|
||||
sb.append( String.format( "\n\n*** %s %s***\n",
|
||||
typ.longName( context ), did ) );
|
||||
SuccessRecord record = recordFor( typ, false );
|
||||
tmp = LocUtils.getString( context, record.successNewer?
|
||||
R.string.connstat_succ :
|
||||
|
|
|
@ -109,7 +109,7 @@ public class DBHelper extends SQLiteOpenHelper {
|
|||
|
||||
private static final String[][] s_summaryColsAndTypes = {
|
||||
{ "rowid", "INTEGER PRIMARY KEY AUTOINCREMENT" }
|
||||
,{ VISID, "INTEGER" }
|
||||
,{ VISID, "INTEGER" } // user-visible ID
|
||||
,{ GAME_NAME, "TEXT" }
|
||||
,{ NUM_MOVES, "INTEGER" }
|
||||
,{ TURN, "INTEGER" }
|
||||
|
|
|
@ -1025,10 +1025,18 @@ public class DBUtils {
|
|||
public long m_rowid;
|
||||
public long m_nextNag;
|
||||
public long m_lastMoveMillis;
|
||||
public NeedsNagInfo( long rowid, long nextNag, long lastMove ) {
|
||||
private boolean m_isSolo;
|
||||
|
||||
public NeedsNagInfo( long rowid, long nextNag, long lastMove,
|
||||
CurGameInfo.DeviceRole role ) {
|
||||
m_rowid = rowid;
|
||||
m_nextNag = nextNag;
|
||||
m_lastMoveMillis = 1000 * lastMove;
|
||||
m_isSolo = CurGameInfo.DeviceRole.SERVER_STANDALONE == role;
|
||||
}
|
||||
|
||||
public boolean isSolo() {
|
||||
return m_isSolo;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1036,7 +1044,8 @@ public class DBUtils {
|
|||
{
|
||||
NeedsNagInfo[] result = null;
|
||||
long now = new Date().getTime(); // in milliseconds
|
||||
String[] columns = { ROW_ID, DBHelper.NEXTNAG, DBHelper.LASTMOVE };
|
||||
String[] columns = { ROW_ID, DBHelper.NEXTNAG, DBHelper.LASTMOVE,
|
||||
DBHelper.SERVERROLE };
|
||||
// where nextnag > 0 AND nextnag < now
|
||||
String selection =
|
||||
String.format( "%s > 0 AND %s < %s", DBHelper.NEXTNAG,
|
||||
|
@ -1052,11 +1061,14 @@ public class DBUtils {
|
|||
int rowIndex = cursor.getColumnIndex(ROW_ID);
|
||||
int nagIndex = cursor.getColumnIndex( DBHelper.NEXTNAG );
|
||||
int lastMoveIndex = cursor.getColumnIndex( DBHelper.LASTMOVE );
|
||||
int roleIndex = cursor.getColumnIndex( DBHelper.SERVERROLE );
|
||||
for ( int ii = 0; ii < result.length && cursor.moveToNext(); ++ii ) {
|
||||
long rowid = cursor.getLong( rowIndex );
|
||||
long nextNag = cursor.getLong( nagIndex );
|
||||
long lastMove = cursor.getLong( lastMoveIndex );
|
||||
result[ii] = new NeedsNagInfo( rowid, nextNag, lastMove );
|
||||
CurGameInfo.DeviceRole role =
|
||||
CurGameInfo.DeviceRole.values()[cursor.getInt( roleIndex )];
|
||||
result[ii] = new NeedsNagInfo( rowid, nextNag, lastMove, role );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1762,10 +1774,15 @@ public class DBUtils {
|
|||
|
||||
public static boolean gameDBExists( Context context )
|
||||
{
|
||||
String name = DBHelper.getDBName();
|
||||
File sdcardDB = new File( Environment.getExternalStorageDirectory(),
|
||||
name );
|
||||
return sdcardDB.exists();
|
||||
String varName = getVariantDBName();
|
||||
boolean exists = new File( Environment.getExternalStorageDirectory(),
|
||||
varName ).exists();
|
||||
if ( !exists ) {
|
||||
// try the old one
|
||||
exists = new File( Environment.getExternalStorageDirectory(),
|
||||
DBHelper.getDBName() ).exists();
|
||||
}
|
||||
return exists;
|
||||
}
|
||||
|
||||
public static String[] getColumns( SQLiteDatabase db, String name )
|
||||
|
@ -2044,20 +2061,39 @@ public class DBUtils {
|
|||
return dflt;
|
||||
}
|
||||
|
||||
// public static void setIntFor( Context context, String key, int value )
|
||||
// {
|
||||
// String asStr = String.format( "%d", value );
|
||||
// setStringFor( context, key, asStr );
|
||||
// }
|
||||
public static void setIntFor( Context context, String key, int value )
|
||||
{
|
||||
DbgUtils.logdf( "DBUtils.setIntFor(key=%s, val=%d)", key, value );
|
||||
String asStr = String.format( "%d", value );
|
||||
setStringFor( context, key, asStr );
|
||||
}
|
||||
|
||||
// public static int getIntFor( Context context, String key, int dflt )
|
||||
// {
|
||||
// String asStr = getStringFor( context, key, null );
|
||||
// if ( null != asStr ) {
|
||||
// dflt = Integer.parseInt( asStr );
|
||||
// }
|
||||
// return dflt;
|
||||
// }
|
||||
public static int getIntFor( Context context, String key, int dflt )
|
||||
{
|
||||
String asStr = getStringFor( context, key, null );
|
||||
if ( null != asStr ) {
|
||||
dflt = Integer.parseInt( asStr );
|
||||
}
|
||||
DbgUtils.logdf( "DBUtils.getIntFor(key=%s)=>%d", key, dflt );
|
||||
return dflt;
|
||||
}
|
||||
|
||||
public static void setBoolFor( Context context, String key, boolean value )
|
||||
{
|
||||
// DbgUtils.logdf( "DBUtils.setBoolFor(key=%s, val=%b)", key, value );
|
||||
String asStr = String.format( "%b", value );
|
||||
setStringFor( context, key, asStr );
|
||||
}
|
||||
|
||||
public static boolean getBoolFor( Context context, String key, boolean dflt )
|
||||
{
|
||||
String asStr = getStringFor( context, key, null );
|
||||
if ( null != asStr ) {
|
||||
dflt = Boolean.parseBoolean( asStr );
|
||||
}
|
||||
DbgUtils.logdf( "DBUtils.getBoolFor(key=%s)=>%b", key, dflt );
|
||||
return dflt;
|
||||
}
|
||||
|
||||
public static int getIncrementIntFor( Context context, String key, int dflt,
|
||||
final int incr )
|
||||
|
@ -2097,8 +2133,16 @@ public class DBUtils {
|
|||
{
|
||||
String name = DBHelper.getDBName();
|
||||
File gamesDB = context.getDatabasePath( name );
|
||||
|
||||
// Use the variant name EXCEPT where we're copying from sdCard and
|
||||
// only the older name exists.
|
||||
File sdcardDB = new File( Environment.getExternalStorageDirectory(),
|
||||
name );
|
||||
getVariantDBName() );
|
||||
if ( !toSDCard && !sdcardDB.exists() ) {
|
||||
sdcardDB = new File( Environment.getExternalStorageDirectory(),
|
||||
name );
|
||||
}
|
||||
|
||||
try {
|
||||
File srcDB = toSDCard? gamesDB : sdcardDB;
|
||||
if ( srcDB.exists() ) {
|
||||
|
@ -2113,6 +2157,12 @@ public class DBUtils {
|
|||
}
|
||||
}
|
||||
|
||||
private static String getVariantDBName()
|
||||
{
|
||||
return String.format( "%s_%s", DBHelper.getDBName(),
|
||||
BuildConstants.VARIANT );
|
||||
}
|
||||
|
||||
// Chat is independent of the GameLock mechanism because it's not
|
||||
// touching the SNAPSHOT column.
|
||||
private static void saveChatHistory( Context context, long rowid,
|
||||
|
|
|
@ -111,13 +111,10 @@ public class DbgUtils {
|
|||
|
||||
public static void printStack( StackTraceElement[] trace )
|
||||
{
|
||||
if ( s_doLog ) {
|
||||
if ( null == trace ) {
|
||||
DbgUtils.logf( "printStack(): null trace" );
|
||||
} else {
|
||||
for ( int ii = 0; ii < trace.length; ++ii ) {
|
||||
DbgUtils.logf( "ste %d: %s", ii, trace[ii].toString() );
|
||||
}
|
||||
if ( s_doLog && null != trace ) {
|
||||
// 2: skip printStack etc.
|
||||
for ( int ii = 2; ii < trace.length; ++ii ) {
|
||||
DbgUtils.logf( "ste %d: %s", ii, trace[ii].toString() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
package org.eehouse.android.xw4;
|
||||
|
||||
import android.view.ContextMenu;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
|
@ -76,12 +78,15 @@ public class DelegateBase implements DlgClickNotify,
|
|||
protected void onSaveInstanceState( Bundle outState ) {}
|
||||
public boolean onPrepareOptionsMenu( Menu menu ) { return false; }
|
||||
public boolean onOptionsItemSelected( MenuItem item ) { return false; }
|
||||
public void onCreateContextMenu( ContextMenu menu, View view,
|
||||
ContextMenuInfo menuInfo ) {}
|
||||
public boolean onContextItemSelected( MenuItem item ) { return false; }
|
||||
protected void onStart() {}
|
||||
protected void onStop() {}
|
||||
protected void onDestroy() {}
|
||||
protected void onWindowFocusChanged( boolean hasFocus ) {}
|
||||
protected boolean onBackPressed() { return false; }
|
||||
protected void onActivityResult( int requestCode, int resultCode,
|
||||
protected void onActivityResult( RequestCode requestCode, int resultCode,
|
||||
Intent data )
|
||||
{
|
||||
DbgUtils.logf( "DelegateBase.onActivityResult(): subclass responsibility!!!" );
|
||||
|
@ -174,9 +179,10 @@ public class DelegateBase implements DlgClickNotify,
|
|||
return m_activity.getTitle().toString();
|
||||
}
|
||||
|
||||
protected void startActivityForResult( Intent intent, int requestCode )
|
||||
protected void startActivityForResult( Intent intent,
|
||||
RequestCode requestCode )
|
||||
{
|
||||
m_activity.startActivityForResult( intent, requestCode );
|
||||
m_activity.startActivityForResult( intent, requestCode.ordinal() );
|
||||
}
|
||||
|
||||
protected void setResult( int result, Intent intent )
|
||||
|
@ -431,6 +437,13 @@ public class DelegateBase implements DlgClickNotify,
|
|||
m_dlgDelegate.showConfirmThen( msgID, action );
|
||||
}
|
||||
|
||||
public void showConfirmThen( Runnable onNA, String msg, int posButton,
|
||||
int negButton, Action action, Object... params )
|
||||
{
|
||||
m_dlgDelegate.showConfirmThen( onNA, msg, posButton, negButton, action,
|
||||
params );
|
||||
}
|
||||
|
||||
protected boolean post( Runnable runnable )
|
||||
{
|
||||
return m_dlgDelegate.post( runnable );
|
||||
|
|
|
@ -21,9 +21,16 @@ package org.eehouse.android.xw4;
|
|||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.ListView;
|
||||
|
||||
public interface Delegator {
|
||||
Activity getActivity();
|
||||
Bundle getArguments();
|
||||
void finish();
|
||||
|
||||
// For activities with lists
|
||||
void setListAdapter( ListAdapter adapter );
|
||||
ListAdapter getListAdapter();
|
||||
ListView getListView();
|
||||
}
|
||||
|
|
149
xwords4/android/XWords4/src/org/eehouse/android/xw4/DevID.java
Normal file
149
xwords4/android/XWords4/src/org/eehouse/android/xw4/DevID.java
Normal file
|
@ -0,0 +1,149 @@
|
|||
/* -*- compile-command: "find-and-ant.sh debug install"; -*- */
|
||||
/*
|
||||
* Copyright 2010 - 2015 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;
|
||||
|
||||
/* The relay issues an identifier for a registered device. It's a string
|
||||
* representation of a 32-bit hex number. When devices register, they pass
|
||||
* what's meant to be a unique identifier of their own. GCM-aware devices (for
|
||||
* which this was originally conceived) pass their GCM IDs (which can change,
|
||||
* and require re-registration). Other devices generate an ID however they
|
||||
* choose, or can pass "", meaning "I'm anonymous; just give me an ID based on
|
||||
* nothing."
|
||||
*/
|
||||
|
||||
import android.content.Context;
|
||||
import com.google.android.gcm.GCMRegistrar;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
public class DevID {
|
||||
|
||||
private static final String DEVID_KEY = "DevID.devid_key";
|
||||
private static final String DEVID_ACK_KEY = "key_relay_regid_ackd";
|
||||
private static final String GCM_REGVERS_KEY = "key_gcmvers_regid";
|
||||
|
||||
private static String s_relayDevID;
|
||||
private static int s_asInt;
|
||||
|
||||
// Called, likely on DEBUG builds only, when the relay hostname is
|
||||
// changed. DevIDs are invalid at that point.
|
||||
public static void hostChanged( Context context )
|
||||
{
|
||||
clearRelayDevID( context );
|
||||
RelayService.reset( context );
|
||||
}
|
||||
|
||||
public static int getRelayDevIDInt( Context context )
|
||||
{
|
||||
if ( 0 == s_asInt ) {
|
||||
String asStr = getRelayDevID( context );
|
||||
if ( null != asStr && 0 < asStr.length() ) {
|
||||
s_asInt = Integer.valueOf( asStr, 16 );
|
||||
}
|
||||
}
|
||||
return s_asInt;
|
||||
}
|
||||
|
||||
public static String getRelayDevID( Context context, boolean insistAckd )
|
||||
{
|
||||
String result = getRelayDevID( context );
|
||||
if ( insistAckd && null != result && 0 < result.length()
|
||||
&& ! DBUtils.getBoolFor( context, DEVID_ACK_KEY, false ) ) {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String getRelayDevID( Context context )
|
||||
{
|
||||
if ( null == s_relayDevID ) {
|
||||
String asStr = DBUtils.getStringFor( context, DEVID_KEY, "" );
|
||||
// TRANSITIONAL: If it's not there, see if it's stored the old way
|
||||
if ( 0 == asStr.length() ) {
|
||||
asStr = XWPrefs.getPrefsString( context, R.string.key_relay_regid );
|
||||
}
|
||||
|
||||
if ( null != asStr && 0 != asStr.length() ) {
|
||||
s_relayDevID = asStr;
|
||||
}
|
||||
}
|
||||
DbgUtils.logdf( "DevID.getRelayDevID() => %s", s_relayDevID );
|
||||
return s_relayDevID;
|
||||
}
|
||||
|
||||
public static void setRelayDevID( Context context, String devID )
|
||||
{
|
||||
DbgUtils.logdf( "DevID.setRelayDevID()" );
|
||||
if ( BuildConfig.DEBUG ) {
|
||||
String oldID = getRelayDevID( context );
|
||||
if ( null != oldID && 0 < oldID.length()
|
||||
&& ! devID.equals( oldID ) ) {
|
||||
DbgUtils.logdf( "devID changing!!!: %s => %s", oldID, devID );
|
||||
}
|
||||
}
|
||||
DBUtils.setStringFor( context, DEVID_KEY, devID );
|
||||
s_relayDevID = devID;
|
||||
|
||||
DBUtils.setBoolFor( context, DEVID_ACK_KEY, true );
|
||||
// DbgUtils.printStack();
|
||||
}
|
||||
|
||||
public static void clearRelayDevID( Context context )
|
||||
{
|
||||
DbgUtils.logf( "DevID.clearRelayDevID()" );
|
||||
DBUtils.setStringFor( context, DEVID_KEY, "" );
|
||||
// DbgUtils.printStack();
|
||||
}
|
||||
|
||||
public static void setGCMDevID( Context context, String devID )
|
||||
{
|
||||
int curVers = Utils.getAppVersion( context );
|
||||
DBUtils.setIntFor( context, GCM_REGVERS_KEY, curVers );
|
||||
DBUtils.setBoolFor( context, DEVID_ACK_KEY, false );
|
||||
}
|
||||
|
||||
public static String getGCMDevID( Context context )
|
||||
{
|
||||
int curVers = Utils.getAppVersion( context );
|
||||
int storedVers = DBUtils.getIntFor( context, GCM_REGVERS_KEY, 0 );
|
||||
// TRANSITIONAL
|
||||
if ( 0 == storedVers ) {
|
||||
storedVers = XWPrefs.getPrefsInt( context,
|
||||
R.string.key_gcmvers_regid, 0 );
|
||||
if ( 0 != storedVers ) {
|
||||
DBUtils.setIntFor( context, GCM_REGVERS_KEY, storedVers );
|
||||
}
|
||||
}
|
||||
|
||||
String result;
|
||||
if ( 0 != storedVers && storedVers < curVers ) {
|
||||
result = ""; // Don't trust what registrar has
|
||||
} else {
|
||||
result = GCMRegistrar.getRegistrationId( context );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void clearGCMDevID( Context context )
|
||||
{
|
||||
DBUtils.setBoolFor( context, DEVID_ACK_KEY, false );
|
||||
}
|
||||
}
|
|
@ -22,7 +22,7 @@ package org.eehouse.android.xw4;
|
|||
|
||||
import android.os.Bundle;
|
||||
|
||||
public class DictBrowseActivity extends XWListActivity {
|
||||
public class DictBrowseActivity extends XWActivity {
|
||||
|
||||
private DictBrowseDelegate m_dlgt;
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
package org.eehouse.android.xw4;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ListActivity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.DataSetObserver;
|
||||
|
@ -156,7 +155,7 @@ public class DictBrowseDelegate extends ListDelegateBase
|
|||
}
|
||||
}
|
||||
|
||||
protected DictBrowseDelegate( ListDelegator delegator, Bundle savedInstanceState )
|
||||
protected DictBrowseDelegate( Delegator delegator, Bundle savedInstanceState )
|
||||
{
|
||||
super( delegator, savedInstanceState, R.layout.dict_browser );
|
||||
m_activity = delegator.getActivity();
|
||||
|
|
|
@ -33,7 +33,7 @@ import java.util.HashMap;
|
|||
import org.eehouse.android.xw4.DictUtils.DictAndLoc;
|
||||
import org.eehouse.android.xw4.loc.LocUtils;
|
||||
|
||||
public class DictsActivity extends XWListActivity {
|
||||
public class DictsActivity extends XWActivity {
|
||||
|
||||
private static interface SafePopup {
|
||||
public void doPopup( Context context, View button,
|
||||
|
|
|
@ -23,7 +23,6 @@ package org.eehouse.android.xw4;
|
|||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.app.ListActivity;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface.OnCancelListener;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
|
@ -47,7 +46,7 @@ import android.widget.LinearLayout;
|
|||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import java.net.HttpURLConnection;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
@ -300,7 +299,7 @@ public class DictsDelegate extends ListDelegateBase
|
|||
}
|
||||
}
|
||||
|
||||
protected DictsDelegate( ListDelegator delegator, Bundle savedInstanceState )
|
||||
protected DictsDelegate( Delegator delegator, Bundle savedInstanceState )
|
||||
{
|
||||
super( delegator, savedInstanceState, R.layout.dict_browse,
|
||||
R.menu.dicts_menu );
|
||||
|
@ -985,7 +984,7 @@ public class DictsDelegate extends ListDelegateBase
|
|||
// return mkDownloadIntent( context, dict_url );
|
||||
}
|
||||
|
||||
public static void downloadForResult( Activity activity, int requestCode,
|
||||
public static void downloadForResult( Activity activity, RequestCode requestCode,
|
||||
int lang, String name )
|
||||
{
|
||||
Intent intent = new Intent( activity, DictsActivity.class );
|
||||
|
@ -998,16 +997,16 @@ public class DictsDelegate extends ListDelegateBase
|
|||
intent.putExtra( DICT_NAME_EXTRA, name );
|
||||
}
|
||||
|
||||
activity.startActivityForResult( intent, requestCode );
|
||||
activity.startActivityForResult( intent, requestCode.ordinal() );
|
||||
}
|
||||
|
||||
public static void downloadForResult( Activity activity, int requestCode,
|
||||
public static void downloadForResult( Activity activity, RequestCode requestCode,
|
||||
int lang )
|
||||
{
|
||||
downloadForResult( activity, requestCode, lang, null );
|
||||
}
|
||||
|
||||
public static void downloadForResult( Activity activity, int requestCode )
|
||||
public static void downloadForResult( Activity activity, RequestCode requestCode )
|
||||
{
|
||||
downloadForResult( activity, requestCode, 0, null );
|
||||
}
|
||||
|
@ -1135,11 +1134,11 @@ public class DictsDelegate extends ListDelegateBase
|
|||
// parse less data
|
||||
String name = null;
|
||||
String proc = String.format( "listDicts?lc=%s", m_lc );
|
||||
HttpPost post = NetUtils.makePost( m_context, proc );
|
||||
if ( null != post ) {
|
||||
HttpURLConnection conn = NetUtils.makeHttpConn( m_context, proc );
|
||||
if ( null != conn ) {
|
||||
JSONObject theOne = null;
|
||||
String langName = null;
|
||||
String json = NetUtils.runPost( post, new JSONObject() );
|
||||
String json = NetUtils.runConn( conn, new JSONObject() );
|
||||
if ( null != json ) {
|
||||
try {
|
||||
JSONObject obj = new JSONObject( json );
|
||||
|
@ -1217,9 +1216,9 @@ public class DictsDelegate extends ListDelegateBase
|
|||
public Boolean doInBackground( Void... unused )
|
||||
{
|
||||
boolean success = false;
|
||||
HttpPost post = NetUtils.makePost( m_context, "listDicts" );
|
||||
if ( null != post ) {
|
||||
String json = NetUtils.runPost( post, new JSONObject() );
|
||||
HttpURLConnection conn = NetUtils.makeHttpConn( m_context, "listDicts" );
|
||||
if ( null != conn ) {
|
||||
String json = NetUtils.runConn( conn, new JSONObject() );
|
||||
if ( !isCancelled() ) {
|
||||
if ( null != json ) {
|
||||
post( new Runnable() {
|
||||
|
|
|
@ -65,6 +65,7 @@ public class DlgDelegate {
|
|||
NEW_GAME_PRESSED,
|
||||
SET_HIDE_NEWGAME_BUTTONS,
|
||||
DWNLD_LOC_DICT,
|
||||
NEW_GAME_DFLT_NAME,
|
||||
|
||||
// BoardDelegate
|
||||
UNDO_LAST_ACTION,
|
||||
|
@ -138,7 +139,7 @@ public class DlgDelegate {
|
|||
|
||||
public interface DlgClickNotify {
|
||||
public static enum InviteMeans {
|
||||
SMS, EMAIL, NFC, BLUETOOTH, CLIPBOARD,
|
||||
SMS, EMAIL, NFC, BLUETOOTH, CLIPBOARD, RELAY,
|
||||
};
|
||||
void dlgButtonClicked( Action action, int button, Object[] params );
|
||||
void inviteChoiceMade( Action action, InviteMeans means, Object[] params );
|
||||
|
@ -561,7 +562,7 @@ public class DlgDelegate {
|
|||
|
||||
private Dialog createNotAgainDialog( final DlgState state, DlgID dlgID )
|
||||
{
|
||||
NotAgainView naView = (NotAgainView)
|
||||
final NotAgainView naView = (NotAgainView)
|
||||
LocUtils.inflate( m_activity, R.layout.not_again_view );
|
||||
naView.setMessage( state.m_msg );
|
||||
final OnClickListener lstnr_p = mkCallbackClickListener( state, naView );
|
||||
|
@ -571,18 +572,15 @@ public class DlgDelegate {
|
|||
.setView( naView )
|
||||
.setPositiveButton( android.R.string.ok, lstnr_p );
|
||||
|
||||
// Adding third button doesn't work for some reason. Either this
|
||||
// feature goes away or the "do not show again" becomes a checkbox as
|
||||
// many apps do it.
|
||||
if ( null != state.m_pair ) {
|
||||
final ActionPair more = state.m_pair;
|
||||
OnClickListener lstnr = new OnClickListener() {
|
||||
public void onClick( DialogInterface dlg, int item ) {
|
||||
checkNotAgainCheck( state, naView );
|
||||
m_clickCallback.
|
||||
dlgButtonClicked( more.action,
|
||||
AlertDialog.BUTTON_POSITIVE,
|
||||
more.params );
|
||||
lstnr_p.onClick( dlg, AlertDialog.BUTTON_POSITIVE );
|
||||
}
|
||||
};
|
||||
builder.setNegativeButton( more.buttonStr, lstnr );
|
||||
|
@ -631,6 +629,10 @@ public class DlgDelegate {
|
|||
items.add( getString( R.string.invite_choice_nfc ) );
|
||||
means.add( DlgClickNotify.InviteMeans.NFC );
|
||||
}
|
||||
if ( XWApp.RELAYINVITE_SUPPORTED ) {
|
||||
items.add( getString( R.string.invite_choice_relay ) );
|
||||
means.add( DlgClickNotify.InviteMeans.RELAY );
|
||||
}
|
||||
final int clipPos = means.size();
|
||||
items.add( getString( R.string.slmenu_copy_sel ) );
|
||||
means.add( DlgClickNotify.InviteMeans.CLIPBOARD );
|
||||
|
@ -762,14 +764,7 @@ public class DlgDelegate {
|
|||
OnClickListener cbkOnClickLstnr;
|
||||
cbkOnClickLstnr = new OnClickListener() {
|
||||
public void onClick( DialogInterface dlg, int button ) {
|
||||
if ( null != naView && naView.getChecked() ) {
|
||||
if ( 0 != state.m_prefsKey ) {
|
||||
XWPrefs.setPrefsBoolean( m_activity, state.m_prefsKey,
|
||||
true );
|
||||
} else if ( null != state.m_onNAChecked ) {
|
||||
state.m_onNAChecked.run();
|
||||
}
|
||||
}
|
||||
checkNotAgainCheck( state, naView );
|
||||
|
||||
if ( Action.SKIP_CALLBACK != state.m_action ) {
|
||||
m_clickCallback.dlgButtonClicked( state.m_action,
|
||||
|
@ -781,6 +776,18 @@ public class DlgDelegate {
|
|||
return cbkOnClickLstnr;
|
||||
}
|
||||
|
||||
private void checkNotAgainCheck( DlgState state, NotAgainView naView )
|
||||
{
|
||||
if ( null != naView && naView.getChecked() ) {
|
||||
if ( 0 != state.m_prefsKey ) {
|
||||
XWPrefs.setPrefsBoolean( m_activity, state.m_prefsKey,
|
||||
true );
|
||||
} else if ( null != state.m_onNAChecked ) {
|
||||
state.m_onNAChecked.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Dialog setCallbackDismissListener( final Dialog dialog,
|
||||
final DlgState state,
|
||||
DlgID dlgID )
|
||||
|
|
|
@ -70,4 +70,5 @@ public enum DlgID {
|
|||
, DLG_GETDICT
|
||||
, GAMES_LIST_NEWGAME
|
||||
, CHANGE_CONN
|
||||
, GAMES_LIST_NAME_REMATCH
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ import android.app.Activity;
|
|||
import android.os.Bundle;
|
||||
import android.view.Window;
|
||||
|
||||
public class DwnldActivity extends XWListActivity {
|
||||
public class DwnldActivity extends XWActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate( Bundle savedInstanceState )
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
package org.eehouse.android.xw4;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ListActivity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
|
@ -69,7 +68,7 @@ public class DwnldDelegate extends ListDelegateBase {
|
|||
void gotDictInfo( boolean success, String lc, String name );
|
||||
}
|
||||
|
||||
public DwnldDelegate( ListDelegator delegator, Bundle savedInstanceState )
|
||||
public DwnldDelegate( Delegator delegator, Bundle savedInstanceState )
|
||||
{
|
||||
super( delegator, savedInstanceState, R.layout.import_dict );
|
||||
m_activity = delegator.getActivity();
|
||||
|
|
|
@ -30,6 +30,7 @@ import android.graphics.drawable.ColorDrawable;
|
|||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Handler;
|
||||
import android.view.View;
|
||||
import java.lang.ref.WeakReference;
|
||||
import junit.framework.Assert;
|
||||
|
||||
public class ExpiringDelegate {
|
||||
|
@ -210,7 +211,7 @@ public class ExpiringDelegate {
|
|||
long nextStartIn = lastStart + onePct - now;
|
||||
// DbgUtils.logf( "pct change %d seconds from now", nextStartIn );
|
||||
|
||||
m_handler.postDelayed( mkRunnable(), 1000 * nextStartIn ); // NPE
|
||||
m_handler.postDelayed( mkRunnable(), 1000 * nextStartIn );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -218,27 +219,39 @@ public class ExpiringDelegate {
|
|||
private Runnable mkRunnable()
|
||||
{
|
||||
if ( null == m_runnable ) {
|
||||
m_runnable = new Runnable() {
|
||||
public void run() {
|
||||
m_runnable = mkRunnable( this );
|
||||
}
|
||||
return m_runnable;
|
||||
}
|
||||
|
||||
private static Runnable mkRunnable( ExpiringDelegate self )
|
||||
{
|
||||
final WeakReference<ExpiringDelegate> selfRef
|
||||
= new WeakReference<ExpiringDelegate>( self );
|
||||
return new Runnable() {
|
||||
public void run() {
|
||||
ExpiringDelegate dlgt = selfRef.get();
|
||||
if ( null != dlgt ) {
|
||||
if ( XWApp.DEBUG_EXP_TIMERS ) {
|
||||
DbgUtils.logf( "ExpiringDelegate: timer fired"
|
||||
+ " for %H", this );
|
||||
}
|
||||
if ( m_active ) {
|
||||
figurePct();
|
||||
if ( m_haveTurnLocal ) {
|
||||
m_back = null;
|
||||
setBackground();
|
||||
if ( dlgt.m_active ) {
|
||||
dlgt.figurePct();
|
||||
if ( dlgt.m_haveTurnLocal ) {
|
||||
dlgt.m_back = null;
|
||||
dlgt.setBackground();
|
||||
}
|
||||
if ( XWApp.DEBUG_EXP_TIMERS ) {
|
||||
DbgUtils.logf( "ExpiringDelegate: invalidating"
|
||||
+ " view %H", m_view );
|
||||
+ " view %H", dlgt.m_view );
|
||||
}
|
||||
m_view.invalidate();
|
||||
dlgt.m_view.invalidate();
|
||||
}
|
||||
} else {
|
||||
DbgUtils.logf( "ExpiringDelegate.run(): reference gc'd" );
|
||||
}
|
||||
};
|
||||
}
|
||||
return m_runnable;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,10 +24,6 @@ import android.app.AlertDialog;
|
|||
import android.content.Context;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
|
||||
import org.eehouse.android.xw4.loc.LocUtils;
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ public class GCMIntentService extends GCMBaseIntentService {
|
|||
protected void onRegistered( Context context, String regId )
|
||||
{
|
||||
DbgUtils.logf( "GCMIntentService.onRegistered(%s)", regId );
|
||||
XWPrefs.setGCMDevID( context, regId );
|
||||
DevID.setGCMDevID( context, regId );
|
||||
notifyRelayService( context, true );
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,7 @@ public class GCMIntentService extends GCMBaseIntentService {
|
|||
protected void onUnregistered( Context context, String regId )
|
||||
{
|
||||
DbgUtils.logf( "GCMIntentService.onUnregistered(%s)", regId );
|
||||
XWPrefs.clearGCMDevID( context );
|
||||
DevID.clearGCMDevID( context );
|
||||
RelayService.devIDChanged();
|
||||
notifyRelayService( context, false );
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ public class GCMIntentService extends GCMBaseIntentService {
|
|||
try {
|
||||
GCMRegistrar.checkDevice( app );
|
||||
// GCMRegistrar.checkManifest( app );
|
||||
String regId = XWPrefs.getGCMDevID( app );
|
||||
String regId = DevID.getGCMDevID( app );
|
||||
if (regId.equals("")) {
|
||||
GCMRegistrar.register( app, GCMConsts.SENDER_ID );
|
||||
}
|
||||
|
|
|
@ -68,8 +68,6 @@ public class GameConfigDelegate extends DelegateBase
|
|||
private static final String INTENT_FORRESULT_ROWID = "forresult";
|
||||
|
||||
private static final String WHICH_PLAYER = "WHICH_PLAYER";
|
||||
private static final int REQUEST_LANG = 1;
|
||||
private static final int REQUEST_DICT = 2;
|
||||
|
||||
private Activity m_activity;
|
||||
private CheckBox m_joinPublicCheck;
|
||||
|
@ -94,7 +92,6 @@ public class GameConfigDelegate extends DelegateBase
|
|||
private boolean m_forResult;
|
||||
private CurGameInfo m_gi;
|
||||
private CurGameInfo m_giOrig;
|
||||
private GameLock m_gameLock;
|
||||
private int m_whichPlayer;
|
||||
// private Spinner m_roleSpinner;
|
||||
// private Spinner m_connectSpinner;
|
||||
|
@ -509,10 +506,6 @@ public class GameConfigDelegate extends DelegateBase
|
|||
|
||||
protected void onPause()
|
||||
{
|
||||
if ( null != m_gameLock ) {
|
||||
m_gameLock.unlock();
|
||||
m_gameLock = null;
|
||||
}
|
||||
m_giOrig = null; // flag for onStart and onResume
|
||||
super.onPause();
|
||||
}
|
||||
|
@ -523,7 +516,7 @@ public class GameConfigDelegate extends DelegateBase
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult( int requestCode, int resultCode, Intent data )
|
||||
protected void onActivityResult( RequestCode requestCode, int resultCode, Intent data )
|
||||
{
|
||||
if ( Activity.RESULT_CANCELED != resultCode ) {
|
||||
loadGame();
|
||||
|
@ -533,7 +526,7 @@ public class GameConfigDelegate extends DelegateBase
|
|||
configDictSpinner( m_dictSpinner, m_gi.dictLang, dictName );
|
||||
configDictSpinner( m_playerDictSpinner, m_gi.dictLang, dictName );
|
||||
break;
|
||||
case REQUEST_LANG:
|
||||
case REQUEST_LANG_GC:
|
||||
String langName = data.getStringExtra( DictsDelegate.RESULT_LAST_LANG );
|
||||
selLangChanged( langName );
|
||||
setLangSpinnerSelection( langName );
|
||||
|
@ -549,10 +542,8 @@ public class GameConfigDelegate extends DelegateBase
|
|||
if ( null == m_giOrig ) {
|
||||
m_giOrig = new CurGameInfo( m_activity );
|
||||
|
||||
// Lock in case we're going to config. We *could* re-get the
|
||||
// lock once the user decides to make changes. PENDING.
|
||||
m_gameLock = new GameLock( m_rowid, true ).lock();
|
||||
int gamePtr = GameUtils.loadMakeGame( m_activity, m_giOrig, m_gameLock );
|
||||
GameLock gameLock = new GameLock( m_rowid, false ).lock();
|
||||
int gamePtr = GameUtils.loadMakeGame( m_activity, m_giOrig, gameLock );
|
||||
if ( 0 == gamePtr ) {
|
||||
showDictGoneFinish();
|
||||
} else {
|
||||
|
@ -564,7 +555,6 @@ public class GameConfigDelegate extends DelegateBase
|
|||
m_gameLockedCheck =
|
||||
(CheckBox)findViewById( R.id.game_locked_check );
|
||||
m_gameLockedCheck.setVisibility( View.VISIBLE );
|
||||
m_gameLockedCheck.setChecked( true );
|
||||
m_gameLockedCheck.setOnClickListener( this );
|
||||
}
|
||||
handleLockedChange();
|
||||
|
@ -581,11 +571,14 @@ public class GameConfigDelegate extends DelegateBase
|
|||
} else if ( !localOnlyGame() ) {
|
||||
String relayName = XWPrefs.getDefaultRelayHost( m_activity );
|
||||
int relayPort = XWPrefs.getDefaultRelayPort( m_activity );
|
||||
XwJNI.comms_getInitialAddr( m_carOrig, relayName, relayPort );
|
||||
XwJNI.comms_getInitialAddr( m_carOrig, relayName,
|
||||
relayPort );
|
||||
}
|
||||
m_conTypes = (CommsConnTypeSet)m_carOrig.conTypes.clone();
|
||||
XwJNI.game_dispose( gamePtr );
|
||||
|
||||
gameLock.unlock();
|
||||
|
||||
m_car = new CommsAddrRec( m_carOrig );
|
||||
|
||||
setTitle();
|
||||
|
@ -698,7 +691,7 @@ public class GameConfigDelegate extends DelegateBase
|
|||
|
||||
public void onClick( View view )
|
||||
{
|
||||
if ( null == m_gameLock ) {
|
||||
if ( isFinishing() ) {
|
||||
// do nothing; we're on the way out
|
||||
} else if ( m_addPlayerButton == view ) {
|
||||
int curIndex = m_gi.nPlayers;
|
||||
|
@ -756,7 +749,7 @@ public class GameConfigDelegate extends DelegateBase
|
|||
protected boolean onBackPressed()
|
||||
{
|
||||
boolean consumed = false;
|
||||
if ( null != m_gameLock ) {
|
||||
if ( ! isFinishing() ) {
|
||||
if ( m_forResult ) {
|
||||
deleteGame();
|
||||
} else {
|
||||
|
@ -778,63 +771,64 @@ public class GameConfigDelegate extends DelegateBase
|
|||
|
||||
private void deleteGame()
|
||||
{
|
||||
if ( null != m_gameLock ) {
|
||||
DBUtils.deleteGame( m_activity, m_gameLock );
|
||||
m_gameLock.unlock();
|
||||
m_gameLock = null;
|
||||
}
|
||||
GameUtils.deleteGame( m_activity, m_rowid, false );
|
||||
}
|
||||
|
||||
private void loadPlayersList()
|
||||
{
|
||||
m_playerLayout.removeAllViews();
|
||||
if ( !isFinishing() ) {
|
||||
m_playerLayout.removeAllViews();
|
||||
|
||||
String[] names = m_gi.visibleNames( false );
|
||||
// only enable delete if one will remain (or two if networked)
|
||||
boolean canDelete = names.length > 2
|
||||
|| (localOnlyGame() && names.length > 1);
|
||||
View.OnClickListener lstnr = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick( View view ) {
|
||||
m_whichPlayer = ((XWListItem)view).getPosition();
|
||||
showDialog( DlgID.PLAYER_EDIT );
|
||||
}
|
||||
};
|
||||
String[] names = m_gi.visibleNames( false );
|
||||
// only enable delete if one will remain (or two if networked)
|
||||
boolean canDelete = names.length > 2
|
||||
|| (localOnlyGame() && names.length > 1);
|
||||
View.OnClickListener lstnr = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick( View view ) {
|
||||
m_whichPlayer = ((XWListItem)view).getPosition();
|
||||
showDialog( DlgID.PLAYER_EDIT );
|
||||
}
|
||||
};
|
||||
|
||||
boolean localGame = localOnlyGame();
|
||||
for ( int ii = 0; ii < names.length; ++ii ) {
|
||||
final XWListItem view = XWListItem.inflate( m_activity, null );
|
||||
view.setPosition( ii );
|
||||
view.setText( names[ii] );
|
||||
if ( localGame && m_gi.players[ii].isLocal ) {
|
||||
view.setComment( m_gi.dictName(ii) );
|
||||
}
|
||||
if ( canDelete ) {
|
||||
view.setDeleteCallback( this );
|
||||
boolean localGame = localOnlyGame();
|
||||
boolean unlocked = null == m_gameLockedCheck
|
||||
|| !m_gameLockedCheck.isChecked();
|
||||
for ( int ii = 0; ii < names.length; ++ii ) {
|
||||
final XWListItem view = XWListItem.inflate( m_activity, null );
|
||||
view.setPosition( ii );
|
||||
view.setText( names[ii] );
|
||||
if ( localGame && m_gi.players[ii].isLocal ) {
|
||||
view.setComment( m_gi.dictName(ii) );
|
||||
}
|
||||
if ( canDelete ) {
|
||||
view.setDeleteCallback( this );
|
||||
}
|
||||
|
||||
view.setEnabled( unlocked );
|
||||
view.setOnClickListener( lstnr );
|
||||
m_playerLayout.addView( view );
|
||||
|
||||
View divider = inflate( R.layout.divider_view );
|
||||
m_playerLayout.addView( divider );
|
||||
}
|
||||
|
||||
view.setOnClickListener( lstnr );
|
||||
m_playerLayout.addView( view );
|
||||
m_addPlayerButton
|
||||
.setVisibility( names.length >= CurGameInfo.MAX_NUM_PLAYERS?
|
||||
View.GONE : View.VISIBLE );
|
||||
m_jugglePlayersButton
|
||||
.setVisibility( names.length <= 1 ?
|
||||
View.GONE : View.VISIBLE );
|
||||
|
||||
View divider = inflate( R.layout.divider_view );
|
||||
m_playerLayout.addView( divider );
|
||||
showHideRelayStuff();
|
||||
|
||||
if ( ! localOnlyGame()
|
||||
&& ((0 == m_gi.remoteCount() )
|
||||
|| (m_gi.nPlayers == m_gi.remoteCount()) ) ) {
|
||||
showDialog( DlgID.FORCE_REMOTE );
|
||||
}
|
||||
adjustPlayersLabel();
|
||||
}
|
||||
|
||||
m_addPlayerButton
|
||||
.setVisibility( names.length >= CurGameInfo.MAX_NUM_PLAYERS?
|
||||
View.GONE : View.VISIBLE );
|
||||
m_jugglePlayersButton
|
||||
.setVisibility( names.length <= 1 ?
|
||||
View.GONE : View.VISIBLE );
|
||||
|
||||
showHideRelayStuff();
|
||||
|
||||
if ( ! localOnlyGame()
|
||||
&& ((0 == m_gi.remoteCount() )
|
||||
|| (m_gi.nPlayers == m_gi.remoteCount()) ) ) {
|
||||
showDialog( DlgID.FORCE_REMOTE );
|
||||
}
|
||||
adjustPlayersLabel();
|
||||
} // loadPlayersList
|
||||
|
||||
private void configDictSpinner( Spinner dictsSpinner, int lang,
|
||||
|
@ -856,7 +850,7 @@ public class GameConfigDelegate extends DelegateBase
|
|||
|
||||
if ( chosen.equals( m_browseText ) ) {
|
||||
DictsDelegate.downloadForResult( m_activity,
|
||||
REQUEST_DICT,
|
||||
RequestCode.REQUEST_DICT,
|
||||
m_gi.dictLang );
|
||||
}
|
||||
}
|
||||
|
@ -885,13 +879,17 @@ public class GameConfigDelegate extends DelegateBase
|
|||
public void onItemSelected(AdapterView<?> parentView,
|
||||
View selectedItemView,
|
||||
int position, long id ) {
|
||||
String chosen =
|
||||
(String)parentView.getItemAtPosition( position );
|
||||
if ( chosen.equals( m_browseText ) ) {
|
||||
DictsDelegate.downloadForResult( m_activity, REQUEST_LANG );
|
||||
} else {
|
||||
String langName = adapter.getLangAtPosition( position );
|
||||
selLangChanged( langName );
|
||||
if ( ! isFinishing() ) { // not on the way out?
|
||||
String chosen =
|
||||
(String)parentView.getItemAtPosition( position );
|
||||
if ( chosen.equals( m_browseText ) ) {
|
||||
DictsDelegate.downloadForResult( m_activity,
|
||||
RequestCode
|
||||
.REQUEST_LANG_GC );
|
||||
} else {
|
||||
String langName = adapter.getLangAtPosition( position );
|
||||
selLangChanged( langName );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1044,7 +1042,15 @@ public class GameConfigDelegate extends DelegateBase
|
|||
m_isLocked = locking;
|
||||
for ( int id : s_disabledWhenLocked ) {
|
||||
View view = findViewById( id );
|
||||
view.setEnabled( !m_isLocked );
|
||||
view.setEnabled( !locking );
|
||||
}
|
||||
|
||||
int nChildren = m_playerLayout.getChildCount();
|
||||
for ( int ii = 0; ii < nChildren; ++ii ) {
|
||||
View child = m_playerLayout.getChildAt( ii );
|
||||
if ( child instanceof XWListItem ) {
|
||||
((XWListItem)child).setEnabled( !locking );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1146,9 +1152,12 @@ public class GameConfigDelegate extends DelegateBase
|
|||
|
||||
private void applyChanges( boolean forceNew )
|
||||
{
|
||||
if ( null != m_gameLock ) {
|
||||
GameUtils.applyChanges( m_activity, m_gi, m_car, m_gameLock,
|
||||
if ( !isFinishing() ) {
|
||||
GameLock gameLock = new GameLock( m_rowid, true ).lock();
|
||||
GameUtils.applyChanges( m_activity, m_gi, m_car, gameLock,
|
||||
forceNew );
|
||||
DBUtils.saveThumbnail( m_activity, gameLock, null ); // clear it
|
||||
gameLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1158,8 +1167,6 @@ public class GameConfigDelegate extends DelegateBase
|
|||
&& 0 == m_car.ip_relay_invite.length() ) {
|
||||
showOKOnlyDialog( R.string.no_empty_rooms );
|
||||
} else {
|
||||
m_gameLock.unlock();
|
||||
m_gameLock = null;
|
||||
GameUtils.launchGameAndFinish( m_activity, m_rowid );
|
||||
}
|
||||
}
|
||||
|
@ -1189,14 +1196,14 @@ public class GameConfigDelegate extends DelegateBase
|
|||
return DeviceRole.SERVER_STANDALONE == m_giOrig.serverRole;
|
||||
}
|
||||
|
||||
public static void editForResult( Activity parent, int requestCode,
|
||||
public static void editForResult( Activity parent, RequestCode requestCode,
|
||||
long rowID )
|
||||
{
|
||||
Intent intent = new Intent( parent, GameConfigActivity.class );
|
||||
intent.setAction( Intent.ACTION_EDIT );
|
||||
intent.putExtra( GameUtils.INTENT_KEY_ROWID, rowID );
|
||||
intent.putExtra( INTENT_FORRESULT_ROWID, true );
|
||||
parent.startActivityForResult( intent, requestCode );
|
||||
parent.startActivityForResult( intent, requestCode.ordinal() );
|
||||
}
|
||||
|
||||
private void setConnLabel()
|
||||
|
|
|
@ -139,8 +139,11 @@ public class GameListGroup extends ExpiringLinearLayout
|
|||
//////////////////////////////////////////////////
|
||||
public boolean onLongClick( View view )
|
||||
{
|
||||
longClicked();
|
||||
return true;
|
||||
boolean handled = ! XWApp.CONTEXT_MENUS_ENABLED;
|
||||
if ( handled ) {
|
||||
longClicked();
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
|
|
|
@ -124,7 +124,7 @@ public class GameListItem extends LinearLayout
|
|||
++m_loadingCount;
|
||||
|
||||
LoadItemTask task = new LoadItemTask();
|
||||
if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ) {
|
||||
if ( false && Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ) {
|
||||
// Actually run these in parallel if the OS supports it
|
||||
task.executeOnExecutor( AsyncTask.THREAD_POOL_EXECUTOR );
|
||||
} else {
|
||||
|
|
|
@ -32,7 +32,7 @@ public class GameLock {
|
|||
private long m_rowid;
|
||||
private boolean m_isForWrite;
|
||||
private int m_lockCount;
|
||||
StackTraceElement[] m_lockTrace;
|
||||
private StackTraceElement[] m_lockTrace;
|
||||
|
||||
private static HashMap<Long, GameLock>
|
||||
s_locks = new HashMap<Long,GameLock>();
|
||||
|
@ -54,9 +54,15 @@ public class GameLock {
|
|||
// see if not doing that causes problems.
|
||||
public boolean tryLock()
|
||||
{
|
||||
return null == tryLockImpl(); // unowned?
|
||||
}
|
||||
|
||||
private GameLock tryLockImpl()
|
||||
{
|
||||
GameLock owner = null;
|
||||
boolean gotIt = false;
|
||||
synchronized( s_locks ) {
|
||||
GameLock owner = s_locks.get( m_rowid );
|
||||
owner = s_locks.get( m_rowid );
|
||||
if ( null == owner ) { // unowned
|
||||
Assert.assertTrue( 0 == m_lockCount );
|
||||
s_locks.put( m_rowid, this );
|
||||
|
@ -64,8 +70,8 @@ public class GameLock {
|
|||
gotIt = true;
|
||||
|
||||
if ( XWApp.DEBUG_LOCKS ) {
|
||||
StackTraceElement[] trace = Thread.currentThread().
|
||||
getStackTrace();
|
||||
StackTraceElement[] trace
|
||||
= Thread.currentThread().getStackTrace();
|
||||
m_lockTrace = new StackTraceElement[trace.length];
|
||||
System.arraycopy( trace, 0, m_lockTrace, 0, trace.length );
|
||||
}
|
||||
|
@ -76,13 +82,17 @@ public class GameLock {
|
|||
Assert.assertTrue( 0 == m_lockCount );
|
||||
++m_lockCount;
|
||||
gotIt = true;
|
||||
owner = null;
|
||||
} else if ( XWApp.DEBUG_LOCKS ) {
|
||||
DbgUtils.logf( "tryLock(): rowid %d already held by lock %H",
|
||||
m_rowid, owner );
|
||||
}
|
||||
}
|
||||
if ( XWApp.DEBUG_LOCKS ) {
|
||||
DbgUtils.logf( "GameLock.tryLock %H (rowid=%d) => %b",
|
||||
this, m_rowid, gotIt );
|
||||
}
|
||||
return gotIt;
|
||||
return owner;
|
||||
}
|
||||
|
||||
// Wait forever (but may assert if too long)
|
||||
|
@ -105,15 +115,16 @@ public class GameLock {
|
|||
}
|
||||
|
||||
for ( ; ; ) {
|
||||
if ( tryLock() ) {
|
||||
GameLock curOwner = tryLockImpl();
|
||||
if ( null == curOwner ) {
|
||||
result = this;
|
||||
break;
|
||||
}
|
||||
if ( XWApp.DEBUG_LOCKS ) {
|
||||
DbgUtils.logf( "GameLock.lock() %H failed; sleeping", this );
|
||||
if ( 0 == sleptTime || sleptTime + SLEEP_TIME >= assertTime ) {
|
||||
DbgUtils.logf( "lock holding stack:", this );
|
||||
DbgUtils.printStack( m_lockTrace );
|
||||
DbgUtils.logf( "lock %H seeking stack:", curOwner );
|
||||
DbgUtils.printStack( curOwner.m_lockTrace );
|
||||
DbgUtils.logf( "lock %H seeking stack:", this );
|
||||
DbgUtils.printStack();
|
||||
}
|
||||
|
|
|
@ -260,7 +260,7 @@ public class GameUtils {
|
|||
return result;
|
||||
}
|
||||
|
||||
public static String makeDefaultName( Context context, boolean isSolo )
|
||||
public static String makeDefaultName( Context context )
|
||||
{
|
||||
int count = DBUtils.getIncrementIntFor( context, DBUtils.KEY_NEWGAMECOUNT, 0, 1 );
|
||||
return LocUtils.getString( context, R.string.game_fmt, count );
|
||||
|
@ -455,18 +455,20 @@ public class GameUtils {
|
|||
|
||||
public static long makeNewMultiGame( Context context, NetLaunchInfo nli )
|
||||
{
|
||||
return makeNewMultiGame( context, nli, null );
|
||||
return makeNewMultiGame( context, nli, (MultiMsgSink)null,
|
||||
(UtilCtxt)null );
|
||||
}
|
||||
|
||||
public static long makeNewMultiGame( Context context, NetLaunchInfo nli,
|
||||
MultiMsgSink sink )
|
||||
MultiMsgSink sink, UtilCtxt util )
|
||||
{
|
||||
DbgUtils.logf( "makeNewMultiGame(nli=%s)", nli.toString() );
|
||||
CommsAddrRec addr = nli.makeAddrRec( context );
|
||||
|
||||
return makeNewMultiGame( context, sink, DBUtils.GROUPID_UNSPEC, addr,
|
||||
new int[] {nli.lang}, new String[] { nli.dict },
|
||||
nli.nPlayersT, nli.nPlayersH, nli.forceChannel,
|
||||
return makeNewMultiGame( context, sink, util, DBUtils.GROUPID_UNSPEC,
|
||||
addr, new int[] {nli.lang},
|
||||
new String[] { nli.dict }, nli.nPlayersT,
|
||||
nli.nPlayersH, nli.forceChannel,
|
||||
nli.inviteID(), nli.gameID(), nli.gameName,
|
||||
false );
|
||||
}
|
||||
|
@ -474,35 +476,41 @@ public class GameUtils {
|
|||
public static long makeNewMultiGame( Context context, long groupID,
|
||||
String gameName )
|
||||
{
|
||||
return makeNewMultiGame( context, groupID, (CommsConnTypeSet)null,
|
||||
gameName );
|
||||
return makeNewMultiGame( context, groupID, null, 0,
|
||||
(CommsConnTypeSet)null, gameName );
|
||||
}
|
||||
|
||||
public static long makeNewMultiGame( Context context, long groupID,
|
||||
CommsConnTypeSet addrSet, String gameName )
|
||||
String dict, int lang,
|
||||
CommsConnTypeSet addrSet,
|
||||
String gameName )
|
||||
{
|
||||
String inviteID = makeRandomID();
|
||||
return makeNewMultiGame( context, groupID, inviteID, addrSet, gameName );
|
||||
return makeNewMultiGame( context, groupID, inviteID, dict, lang,
|
||||
addrSet, gameName );
|
||||
}
|
||||
|
||||
private static long makeNewMultiGame( Context context, long groupID,
|
||||
String inviteID, CommsConnTypeSet addrSet,
|
||||
String inviteID, String dict,
|
||||
int lang, CommsConnTypeSet addrSet,
|
||||
String gameName )
|
||||
{
|
||||
int[] lang = {0};
|
||||
String[] dict = {null};
|
||||
int[] langArray = {lang};
|
||||
String[] dictArray = {dict};
|
||||
if ( null == addrSet ) {
|
||||
addrSet = XWPrefs.getAddrTypes( context );
|
||||
}
|
||||
CommsAddrRec addr = new CommsAddrRec( addrSet );
|
||||
addr.populate( context );
|
||||
int forceChannel = 0;
|
||||
return makeNewMultiGame( context, null, groupID, addr, lang, dict, 2, 1,
|
||||
return makeNewMultiGame( context, (MultiMsgSink)null, (UtilCtxt)null,
|
||||
groupID, addr, langArray, dictArray, 2, 1,
|
||||
forceChannel, inviteID, 0, gameName, true );
|
||||
}
|
||||
|
||||
private static long makeNewMultiGame( Context context, MultiMsgSink sink,
|
||||
long groupID, CommsAddrRec addr,
|
||||
UtilCtxt util, long groupID,
|
||||
CommsAddrRec addr,
|
||||
int[] lang, String[] dict,
|
||||
int nPlayersT, int nPlayersH,
|
||||
int forceChannel, String inviteID,
|
||||
|
@ -535,7 +543,7 @@ public class GameUtils {
|
|||
|
||||
if ( DBUtils.ROWID_NOTFOUND != rowid ) {
|
||||
GameLock lock = new GameLock( rowid, true ).lock();
|
||||
applyChanges( context, sink, gi, addr, inviteID, lock, false );
|
||||
applyChanges( context, sink, gi, util, addr, inviteID, lock, false );
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
|
@ -587,9 +595,10 @@ public class GameUtils {
|
|||
addr = new CommsAddrRec( null, null );
|
||||
}
|
||||
String inviteID = GameUtils.formatGameID( gameID );
|
||||
return makeNewMultiGame( context, sink, groupID, addr, langa, dicta,
|
||||
nPlayersT, nPlayersH, forceChannel,
|
||||
inviteID, gameID, gameName, isHost );
|
||||
return makeNewMultiGame( context, sink, (UtilCtxt)null, groupID, addr,
|
||||
langa, dicta, nPlayersT, nPlayersH,
|
||||
forceChannel, inviteID, gameID, gameName,
|
||||
isHost );
|
||||
}
|
||||
|
||||
// @SuppressLint({ "NewApi", "NewApi", "NewApi", "NewApi" })
|
||||
|
@ -987,13 +996,14 @@ public class GameUtils {
|
|||
CommsAddrRec car, String inviteID,
|
||||
GameLock lock, boolean forceNew )
|
||||
{
|
||||
applyChanges( context, null, gi, car, inviteID, lock, forceNew );
|
||||
applyChanges( context, (MultiMsgSink)null, gi, (UtilCtxt)null, car,
|
||||
inviteID, lock, forceNew );
|
||||
}
|
||||
|
||||
public static void applyChanges( Context context, MultiMsgSink sink,
|
||||
CurGameInfo gi, CommsAddrRec car,
|
||||
String inviteID, GameLock lock,
|
||||
boolean forceNew )
|
||||
CurGameInfo gi, UtilCtxt util,
|
||||
CommsAddrRec car, String inviteID,
|
||||
GameLock lock, boolean forceNew )
|
||||
{
|
||||
// This should be a separate function, commitChanges() or
|
||||
// somesuch. But: do we have a way to save changes to a gi
|
||||
|
@ -1020,7 +1030,9 @@ public class GameUtils {
|
|||
}
|
||||
|
||||
if ( forceNew || !madeGame ) {
|
||||
XwJNI.game_makeNewGame( gamePtr, gi, JNIUtilsImpl.get(context),
|
||||
XwJNI.game_makeNewGame( gamePtr, gi, util,
|
||||
JNIUtilsImpl.get(context),
|
||||
(DrawCtx)null,
|
||||
cp, sink, dictNames, pairs.m_bytes,
|
||||
pairs.m_paths, langName );
|
||||
}
|
||||
|
@ -1078,8 +1090,8 @@ public class GameUtils {
|
|||
{
|
||||
if ( null != bmr ) {
|
||||
Intent intent = GamesListDelegate.makeRowidIntent( context, rowid );
|
||||
String msg;
|
||||
int titleID;
|
||||
String msg = null;
|
||||
int titleID = 0;
|
||||
if ( null != bmr.m_chat ) {
|
||||
titleID = R.string.notify_chat_title_fmt;
|
||||
if ( null != bmr.m_chatFrom ) {
|
||||
|
@ -1089,18 +1101,29 @@ public class GameUtils {
|
|||
} else {
|
||||
msg = bmr.m_chat;
|
||||
}
|
||||
} else {
|
||||
} else if ( null != bmr.m_lmi ) {
|
||||
titleID = R.string.notify_title_fmt;
|
||||
msg = bmr.m_lmi.format( context );
|
||||
msg = bmr.m_lmi.format( context ); // NPE
|
||||
}
|
||||
|
||||
if ( 0 != titleID ) {
|
||||
String title = LocUtils.getString( context, titleID,
|
||||
getName( context, rowid ) );
|
||||
Utils.postNotification( context, intent, title, msg, (int)rowid );
|
||||
}
|
||||
String title = LocUtils.getString( context, titleID,
|
||||
getName( context, rowid ) );
|
||||
Utils.postNotification( context, intent, title, msg, (int)rowid );
|
||||
} else {
|
||||
DbgUtils.logdf( "postMoveNotification(): posting nothing for lack"
|
||||
+ " of brm" );
|
||||
}
|
||||
}
|
||||
|
||||
public static void postInvitedNotification( Context context, int gameID,
|
||||
String body, long rowid )
|
||||
{
|
||||
Intent intent = GamesListDelegate.makeGameIDIntent( context, gameID );
|
||||
Utils.postNotification( context, intent, R.string.invite_notice_title,
|
||||
body, (int)rowid );
|
||||
}
|
||||
|
||||
private static void tellDied( Context context, GameLock lock,
|
||||
boolean informNow )
|
||||
|
|
|
@ -29,14 +29,7 @@ import org.eehouse.android.xw4.jni.CurGameInfo;
|
|||
|
||||
import junit.framework.Assert;
|
||||
|
||||
public class GamesListActivity extends XWListActivity {
|
||||
|
||||
// private static final String RELAYIDS_EXTRA = "relayids";
|
||||
private static final String ROWID_EXTRA = "rowid";
|
||||
private static final String GAMEID_EXTRA = "gameid";
|
||||
private static final String REMATCH_ROWID_EXTRA = "rowid_rm";
|
||||
private static final String ALERT_MSG = "alert_msg";
|
||||
|
||||
public class GamesListActivity extends XWActivity {
|
||||
private GamesListDelegate m_dlgt;
|
||||
|
||||
@Override
|
||||
|
|
|
@ -24,12 +24,14 @@ import android.app.Activity;
|
|||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
@ -80,18 +82,19 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
private static final String SAVE_DICTNAMES = "SAVE_DICTNAMES";
|
||||
private static final String SAVE_NEXTSOLO = "SAVE_NEXTSOLO";
|
||||
|
||||
private static final int REQUEST_LANG = 1;
|
||||
private static final int CONFIG_GAME = 2;
|
||||
|
||||
private static final String RELAYIDS_EXTRA = "relayids";
|
||||
private static final String ROWID_EXTRA = "rowid";
|
||||
private static final String GAMEID_EXTRA = "gameid";
|
||||
private static final String REMATCH_ROWID_EXTRA = "rm_rowid";
|
||||
private static final String REMATCH_DICT_EXTRA = "rm_dict";
|
||||
private static final String REMATCH_LANG_EXTRA = "rm_lang";
|
||||
private static final String REMATCH_NEWNAME_EXTRA = "rm_nnm";
|
||||
private static final String REMATCH_ADDRS_EXTRA = "rm_addrs";
|
||||
private static final String REMATCH_BTADDR_EXTRA = "rm_btaddr";
|
||||
private static final String REMATCH_PHONE_EXTRA = "rm_phone";
|
||||
private static final String REMATCH_RELAYID_EXTRA = "rm_relayid";
|
||||
|
||||
|
||||
private static final String ALERT_MSG = "alert_msg";
|
||||
|
||||
private class GameListAdapter extends XWExpListAdapter {
|
||||
|
@ -561,7 +564,7 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
|
||||
private Activity m_activity;
|
||||
private static GamesListDelegate s_self;
|
||||
private ListDelegator m_delegator;
|
||||
private Delegator m_delegator;
|
||||
private GameListAdapter m_adapter;
|
||||
private Handler m_handler;
|
||||
private String m_missingDict;
|
||||
|
@ -585,8 +588,10 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
private boolean m_nextIsSolo;
|
||||
private Button[] m_newGameButtons;
|
||||
private boolean m_haveShownGetDict;
|
||||
private Intent m_rematchIntent;
|
||||
private Object[] m_newGameParams;
|
||||
|
||||
public GamesListDelegate( ListDelegator delegator, Bundle sis )
|
||||
public GamesListDelegate( Delegator delegator, Bundle sis )
|
||||
{
|
||||
super( delegator, sis, R.layout.game_list, R.menu.games_list_menu );
|
||||
m_delegator = delegator;
|
||||
|
@ -612,7 +617,9 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
public void onClick( DialogInterface dlg, int item ) {
|
||||
// no name, so user must pick
|
||||
if ( null == m_missingDictName ) {
|
||||
DictsDelegate.downloadForResult( m_activity, REQUEST_LANG,
|
||||
DictsDelegate.downloadForResult( m_activity,
|
||||
RequestCode
|
||||
.REQUEST_LANG_GL,
|
||||
m_missingDictLang );
|
||||
} else {
|
||||
DwnldDelegate
|
||||
|
@ -710,7 +717,7 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
String name = m_namer.getName();
|
||||
DBUtils.setGroupName( m_activity,
|
||||
m_groupid, name );
|
||||
m_adapter.reloadGame( m_rowid );
|
||||
reloadGame( m_rowid );
|
||||
mkListAdapter();
|
||||
}
|
||||
};
|
||||
|
@ -810,7 +817,7 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
}
|
||||
CommonPrefs.setDefaultPlayerName( m_activity, name );
|
||||
|
||||
getDictForLangIf(); // hack!!!
|
||||
makeThenLaunchOrConfigure();
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
@ -821,12 +828,12 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
final EditText edit = (EditText)view.findViewById( R.id.edit );
|
||||
lstnr = new OnClickListener() {
|
||||
public void onClick( DialogInterface dlg, int item ) {
|
||||
makeThenLaunchOrConfigure( edit, true );
|
||||
makeThenLaunchOrConfigure( edit, true, false );
|
||||
}
|
||||
};
|
||||
lstnr2 = new OnClickListener() {
|
||||
public void onClick( DialogInterface dlg, int item ) {
|
||||
makeThenLaunchOrConfigure( edit, false );
|
||||
makeThenLaunchOrConfigure( edit, false, false );
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -839,6 +846,23 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
.create();
|
||||
break;
|
||||
|
||||
case GAMES_LIST_NAME_REMATCH:
|
||||
view = (LinearLayout)
|
||||
LocUtils.inflate( m_activity, R.layout.msg_label_and_edit );
|
||||
dialog = makeAlertBuilder()
|
||||
.setView( view )
|
||||
.setTitle( R.string.button_rematch )
|
||||
.setIcon( R.drawable.sologame__gen )
|
||||
.setPositiveButton( android.R.string.ok, new OnClickListener() {
|
||||
public void onClick( DialogInterface dlg, int item ) {
|
||||
EditText edit = (EditText)((Dialog)dlg)
|
||||
.findViewById( R.id.edit );
|
||||
startRematchWithName( edit );
|
||||
}
|
||||
} )
|
||||
.create();
|
||||
break;
|
||||
|
||||
default:
|
||||
dialog = super.onCreateDialog( id );
|
||||
break;
|
||||
|
@ -860,25 +884,38 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
ad.getButton( AlertDialog.BUTTON_NEGATIVE )
|
||||
.setVisibility( canDoDefaults ? View.VISIBLE : View.GONE );
|
||||
|
||||
ad.setIcon( m_nextIsSolo ? R.drawable.sologame__gen
|
||||
: R.drawable.multigame__gen );
|
||||
ad.setTitle( m_nextIsSolo ? R.string.new_game
|
||||
: R.string.new_game_networked);
|
||||
|
||||
String msg = getString( canDoDefaults ? R.string.new_game_message
|
||||
: R.string.new_game_message_nodflt );
|
||||
if ( m_nextIsSolo ) {
|
||||
ad.setTitle( R.string.new_game );
|
||||
ad.setIcon( R.drawable.sologame__gen );
|
||||
} else {
|
||||
ad.setTitle( R.string.new_game_networked );
|
||||
ad.setIcon( R.drawable.multigame__gen );
|
||||
|
||||
if ( !m_nextIsSolo ) {
|
||||
msg += "\n\n" + getString( R.string.new_game_message_net );
|
||||
}
|
||||
TextView edit = (TextView)dialog.findViewById( R.id.msg );
|
||||
edit.setText( msg );
|
||||
edit = (TextView)dialog.findViewById( R.id.edit );
|
||||
edit.setText( GameUtils.makeDefaultName( m_activity, m_nextIsSolo ) );
|
||||
edit.setText( GameUtils.makeDefaultName( m_activity ) );
|
||||
edit.setVisibility( View.VISIBLE );
|
||||
break;
|
||||
|
||||
case GAMES_LIST_NAME_REMATCH:
|
||||
edit = (TextView)dialog.findViewById( R.id.edit );
|
||||
edit.setText( m_rematchIntent
|
||||
.getStringExtra( REMATCH_NEWNAME_EXTRA ) );
|
||||
boolean solo =
|
||||
-1 == m_rematchIntent.getIntExtra( REMATCH_ADDRS_EXTRA, -1 );
|
||||
ad.setIcon( solo ? R.drawable.sologame__gen
|
||||
: R.drawable.multigame__gen );
|
||||
((TextView)dialog.findViewById( R.id.msg ))
|
||||
.setVisibility( View.GONE );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init( Bundle savedInstanceState )
|
||||
{
|
||||
m_handler = new Handler();
|
||||
|
@ -914,9 +951,7 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
|
||||
tryStartsFromIntent( getIntent() );
|
||||
|
||||
if ( !askDefaultNameIf() ) {
|
||||
getDictForLangIf();
|
||||
}
|
||||
getDictForLangIf();
|
||||
|
||||
m_origTitle = getTitle();
|
||||
} // init
|
||||
|
@ -929,7 +964,7 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
m_launchedGames.clear();
|
||||
Assert.assertNotNull( intent );
|
||||
invalRelayIDs( intent.getStringArrayExtra( RELAYIDS_EXTRA ) );
|
||||
m_adapter.reloadGame( intent.getLongExtra( ROWID_EXTRA, -1 ) );
|
||||
reloadGame( intent.getLongExtra( ROWID_EXTRA, -1 ) );
|
||||
tryStartsFromIntent( intent );
|
||||
}
|
||||
|
||||
|
@ -1019,7 +1054,8 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
// OnItemLongClickListener interface
|
||||
public boolean onItemLongClick( AdapterView<?> parent, View view,
|
||||
int position, long id ) {
|
||||
boolean success = view instanceof SelectableItem.LongClickHandler;
|
||||
boolean success = ! XWApp.CONTEXT_MENUS_ENABLED
|
||||
&& view instanceof SelectableItem.LongClickHandler;
|
||||
if ( success ) {
|
||||
((SelectableItem.LongClickHandler)view).longClicked();
|
||||
}
|
||||
|
@ -1044,7 +1080,7 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
if ( DBUtils.ROWIDS_ALL == rowid ) { // all changed
|
||||
mkListAdapter();
|
||||
} else {
|
||||
m_adapter.reloadGame( rowid );
|
||||
reloadGame( rowid );
|
||||
}
|
||||
break;
|
||||
case GAME_CREATED:
|
||||
|
@ -1173,11 +1209,13 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
long curID = (Long)params[0];
|
||||
long newid = GameUtils.dupeGame( m_activity, curID );
|
||||
m_selGames.add( newid );
|
||||
if ( null != m_adapter ) {
|
||||
m_adapter.reloadGame( newid );
|
||||
}
|
||||
reloadGame( newid );
|
||||
break;
|
||||
|
||||
case SET_HIDE_NEWGAME_BUTTONS:
|
||||
XWPrefs.setHideNewgameButtons(m_activity, true);
|
||||
setupButtons();
|
||||
// FALLTHRU
|
||||
case NEW_GAME_PRESSED:
|
||||
handleNewGame( m_nextIsSolo );
|
||||
break;
|
||||
|
@ -1199,10 +1237,6 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
case CLEAR_SELS:
|
||||
clearSelections();
|
||||
break;
|
||||
case SET_HIDE_NEWGAME_BUTTONS:
|
||||
XWPrefs.setHideNewgameButtons( m_activity, true );
|
||||
setupButtons();
|
||||
break;
|
||||
case DWNLD_LOC_DICT:
|
||||
String lang = (String)params[0];
|
||||
String name = (String)params[1];
|
||||
|
@ -1228,19 +1262,28 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
};
|
||||
DwnldDelegate.downloadDictInBack( m_activity, lang, name, lstnr );
|
||||
break;
|
||||
case NEW_GAME_DFLT_NAME:
|
||||
m_newGameParams = params;
|
||||
askDefaultName();
|
||||
break;
|
||||
default:
|
||||
Assert.fail();
|
||||
}
|
||||
} else if ( AlertDialog.BUTTON_NEGATIVE == which ) {
|
||||
if ( Action.NEW_GAME_DFLT_NAME == action ) {
|
||||
m_newGameParams = params;
|
||||
makeThenLaunchOrConfigure();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult( int requestCode, int resultCode,
|
||||
protected void onActivityResult( RequestCode requestCode, int resultCode,
|
||||
Intent data )
|
||||
{
|
||||
boolean cancelled = Activity.RESULT_CANCELED == resultCode;
|
||||
switch ( requestCode ) {
|
||||
case REQUEST_LANG:
|
||||
case REQUEST_LANG_GL:
|
||||
if ( !cancelled ) {
|
||||
DbgUtils.logf( "lang need met" );
|
||||
if ( checkWarnNoDict( m_missingDictRowId ) ) {
|
||||
|
@ -1318,11 +1361,19 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
.contains( XWPrefs.getDefaultNewGameGroup( m_activity ) );
|
||||
Utils.setItemVisible( menu, R.id.games_group_default, enable );
|
||||
|
||||
// Rematch supported if there's one game selected
|
||||
enable = 1 == nGamesSelected;
|
||||
if ( enable ) {
|
||||
enable = BoardDelegate.rematchSupported( m_activity,
|
||||
getSelRowIDs()[0] );
|
||||
}
|
||||
Utils.setItemVisible( menu, R.id.games_game_rematch, enable );
|
||||
|
||||
// Move up/down enabled for groups if not the top-most or bottommost
|
||||
// selected
|
||||
enable = 1 == nGroupsSelected;
|
||||
Utils.setItemVisible( menu, R.id.games_group_moveup,
|
||||
enable && 0 <= selGroupPos );
|
||||
enable && 0 < selGroupPos );
|
||||
Utils.setItemVisible( menu, R.id.games_group_movedown, enable
|
||||
&& (selGroupPos + 1) < groupCount );
|
||||
|
||||
|
@ -1365,10 +1416,10 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
{
|
||||
Assert.assertTrue( m_menuPrepared );
|
||||
|
||||
String msg;
|
||||
int itemID = item.getItemId();
|
||||
boolean handled = true;
|
||||
boolean changeContent = false;
|
||||
boolean dropSels = false;
|
||||
int groupPos = getSelGroupPos();
|
||||
long groupID = DBUtils.GROUPID_UNSPEC;
|
||||
if ( 0 <= groupPos ) {
|
||||
|
@ -1400,10 +1451,6 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
showDialog( DlgID.NEW_GROUP );
|
||||
break;
|
||||
|
||||
case R.id.games_game_config:
|
||||
GameUtils.doConfig( m_activity, selRowIDs[0], GameConfigActivity.class );
|
||||
break;
|
||||
|
||||
case R.id.games_menu_dicts:
|
||||
DictsActivity.start( m_activity );
|
||||
break;
|
||||
|
@ -1455,102 +1502,11 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
showToast( R.string.db_store_done );
|
||||
break;
|
||||
|
||||
// Game menus: one or more games selected
|
||||
case R.id.games_game_delete:
|
||||
String msg = getQuantityString( R.plurals.confirm_seldeletes_fmt,
|
||||
selRowIDs.length, selRowIDs.length );
|
||||
showConfirmThen( msg, R.string.button_delete,
|
||||
Action.DELETE_GAMES, selRowIDs );
|
||||
break;
|
||||
|
||||
case R.id.games_game_move:
|
||||
m_rowids = selRowIDs;
|
||||
showDialog( DlgID.CHANGE_GROUP );
|
||||
break;
|
||||
case R.id.games_game_new_from:
|
||||
dropSels = true; // will select the new game instead
|
||||
showNotAgainDlgThen( R.string.not_again_newfrom,
|
||||
R.string.key_notagain_newfrom,
|
||||
Action.NEW_FROM, selRowIDs[0] );
|
||||
break;
|
||||
case R.id.games_game_copy:
|
||||
final GameSummary smry = DBUtils.getSummary( m_activity, selRowIDs[0] );
|
||||
if ( smry.inRelayGame() ) {
|
||||
showOKOnlyDialog( R.string.no_copy_network );
|
||||
} else {
|
||||
dropSels = true; // will select the new game instead
|
||||
post( new Runnable() {
|
||||
public void run() {
|
||||
Activity self = m_activity;
|
||||
byte[] stream =
|
||||
GameUtils.savedGame( self, selRowIDs[0] );
|
||||
long groupID = XWPrefs
|
||||
.getDefaultNewGameGroup( self );
|
||||
GameLock lock =
|
||||
GameUtils.saveNewGame( self, stream, groupID );
|
||||
DBUtils.saveSummary( self, lock, smry );
|
||||
m_selGames.add( lock.getRowid() );
|
||||
lock.unlock();
|
||||
mkListAdapter();
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case R.id.games_game_reset:
|
||||
doConfirmReset( selRowIDs );
|
||||
break;
|
||||
|
||||
case R.id.games_game_rename:
|
||||
m_rowid = selRowIDs[0];
|
||||
showDialog( DlgID.RENAME_GAME );
|
||||
break;
|
||||
|
||||
// Group menus
|
||||
case R.id.games_group_delete:
|
||||
long dftGroup = XWPrefs.getDefaultNewGameGroup( m_activity );
|
||||
if ( m_selGroupIDs.contains( dftGroup ) ) {
|
||||
msg = getString( R.string.cannot_delete_default_group_fmt,
|
||||
m_adapter.groupName( dftGroup ) );
|
||||
showOKOnlyDialog( msg );
|
||||
} else {
|
||||
long[] groupIDs = getSelGroupIDs();
|
||||
Assert.assertTrue( 0 < groupIDs.length );
|
||||
msg = getQuantityString( R.plurals.groups_confirm_del_fmt,
|
||||
groupIDs.length, groupIDs.length );
|
||||
|
||||
int nGames = 0;
|
||||
for ( long tmp : groupIDs ) {
|
||||
nGames += m_adapter.getChildrenCount( tmp );
|
||||
}
|
||||
if ( 0 < nGames ) {
|
||||
msg += getQuantityString( R.plurals.groups_confirm_del_games_fmt,
|
||||
nGames, nGames );
|
||||
}
|
||||
showConfirmThen( msg, Action.DELETE_GROUPS, groupIDs );
|
||||
}
|
||||
break;
|
||||
case R.id.games_group_default:
|
||||
XWPrefs.setDefaultNewGameGroup( m_activity, groupID );
|
||||
break;
|
||||
case R.id.games_group_rename:
|
||||
m_groupid = groupID;
|
||||
showDialog( DlgID.RENAME_GROUP );
|
||||
break;
|
||||
case R.id.games_group_moveup:
|
||||
moveGroup( groupID, true );
|
||||
break;
|
||||
case R.id.games_group_movedown:
|
||||
moveGroup( groupID, false );
|
||||
break;
|
||||
|
||||
default:
|
||||
handled = false;
|
||||
handled = handleSelGamesItem( itemID, selRowIDs )
|
||||
|| handleSelGroupsItem( itemID, getSelGroupIDs() );
|
||||
}
|
||||
|
||||
if ( dropSels ) {
|
||||
clearSelections();
|
||||
}
|
||||
if ( changeContent ) {
|
||||
mkListAdapter();
|
||||
}
|
||||
|
@ -1558,6 +1514,72 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
return handled;// || super.onOptionsItemSelected( item );
|
||||
}
|
||||
|
||||
public void onCreateContextMenu( ContextMenu menu, View view,
|
||||
ContextMenuInfo menuInfo )
|
||||
{
|
||||
super.onCreateContextMenu( menu, view, menuInfo );
|
||||
|
||||
int id = 0;
|
||||
boolean selected = false;
|
||||
long gameRowID = 0;
|
||||
AdapterView.AdapterContextMenuInfo info
|
||||
= (AdapterView.AdapterContextMenuInfo)menuInfo;
|
||||
View targetView = info.targetView;
|
||||
DbgUtils.logf( "onCreateContextMenu(t=%s)",
|
||||
targetView.getClass().getName() );
|
||||
if ( targetView instanceof GameListItem ) {
|
||||
id = R.menu.games_list_game_menu;
|
||||
|
||||
gameRowID = ((GameListItem)targetView).getRowID();
|
||||
selected = m_selGames.contains( gameRowID );
|
||||
} else if ( targetView instanceof GameListGroup ) {
|
||||
id = R.menu.games_list_group_menu;
|
||||
|
||||
long groupID = ((GameListGroup)targetView).getGroupID();
|
||||
selected = m_selGroupIDs.contains( groupID );
|
||||
} else {
|
||||
Assert.fail();
|
||||
}
|
||||
|
||||
if ( 0 != id ) {
|
||||
m_activity.getMenuInflater().inflate( id, menu );
|
||||
|
||||
int hideId = selected
|
||||
? R.id.games_game_select : R.id.games_game_deselect;
|
||||
Utils.setItemVisible( menu, hideId, false );
|
||||
|
||||
if ( 0 != gameRowID ) {
|
||||
boolean enable = BoardDelegate.rematchSupported( m_activity,
|
||||
gameRowID );
|
||||
Utils.setItemVisible( menu, R.id.games_game_rematch, enable );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onContextItemSelected( MenuItem item )
|
||||
{
|
||||
boolean handled = true;
|
||||
AdapterView.AdapterContextMenuInfo info
|
||||
= (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
|
||||
View targetView = info.targetView;
|
||||
|
||||
int itemID = item.getItemId();
|
||||
if ( ! handleToggleItem( itemID, targetView ) ) {
|
||||
long[] selIds = new long[1];
|
||||
if ( targetView instanceof GameListItem ) {
|
||||
selIds[0] = ((GameListItem)targetView).getRowID();
|
||||
handled = handleSelGamesItem( itemID, selIds );
|
||||
} else if ( targetView instanceof GameListGroup ) {
|
||||
selIds[0] = ((GameListGroup)targetView).getGroupID();
|
||||
handled = handleSelGroupsItem( itemID, selIds );
|
||||
} else {
|
||||
Assert.fail();
|
||||
}
|
||||
}
|
||||
|
||||
return handled || super.onContextItemSelected( item );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// DwnldActivity.DownloadFinishedListener interface
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
@ -1603,6 +1625,154 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
}
|
||||
}
|
||||
|
||||
private void reloadGame( long rowID )
|
||||
{
|
||||
if ( null != m_adapter ) {
|
||||
m_adapter.reloadGame( rowID );
|
||||
}
|
||||
}
|
||||
|
||||
private boolean handleToggleItem( int itemID, View target )
|
||||
{
|
||||
boolean handled;
|
||||
switch( itemID ) {
|
||||
case R.id.games_game_select:
|
||||
case R.id.games_game_deselect:
|
||||
SelectableItem.LongClickHandler toggled
|
||||
= (SelectableItem.LongClickHandler)target;
|
||||
toggled.longClicked();
|
||||
handled = true;
|
||||
break;
|
||||
default:
|
||||
handled = false;
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
private boolean handleSelGamesItem( int itemID, final long[] selRowIDs )
|
||||
{
|
||||
boolean handled = true;
|
||||
boolean dropSels = false;
|
||||
|
||||
switch( itemID ) {
|
||||
case R.id.games_game_delete:
|
||||
String msg = getQuantityString( R.plurals.confirm_seldeletes_fmt,
|
||||
selRowIDs.length, selRowIDs.length );
|
||||
showConfirmThen( msg, R.string.button_delete,
|
||||
Action.DELETE_GAMES, selRowIDs );
|
||||
break;
|
||||
|
||||
case R.id.games_game_rematch:
|
||||
Assert.assertTrue( 1 == selRowIDs.length );
|
||||
BoardDelegate.setupRematchFor( m_activity, selRowIDs[0] );
|
||||
break;
|
||||
|
||||
case R.id.games_game_config:
|
||||
GameUtils.doConfig( m_activity, selRowIDs[0], GameConfigActivity.class );
|
||||
break;
|
||||
|
||||
case R.id.games_game_move:
|
||||
m_rowids = selRowIDs;
|
||||
showDialog( DlgID.CHANGE_GROUP );
|
||||
break;
|
||||
case R.id.games_game_new_from:
|
||||
dropSels = true; // will select the new game instead
|
||||
showNotAgainDlgThen( R.string.not_again_newfrom,
|
||||
R.string.key_notagain_newfrom,
|
||||
Action.NEW_FROM, selRowIDs[0] );
|
||||
break;
|
||||
case R.id.games_game_copy:
|
||||
final GameSummary smry = DBUtils.getSummary( m_activity, selRowIDs[0] );
|
||||
if ( smry.inRelayGame() ) {
|
||||
showOKOnlyDialog( R.string.no_copy_network );
|
||||
} else {
|
||||
dropSels = true; // will select the new game instead
|
||||
post( new Runnable() {
|
||||
public void run() {
|
||||
Activity self = m_activity;
|
||||
byte[] stream =
|
||||
GameUtils.savedGame( self, selRowIDs[0] );
|
||||
long groupID = XWPrefs
|
||||
.getDefaultNewGameGroup( self );
|
||||
GameLock lock =
|
||||
GameUtils.saveNewGame( self, stream, groupID );
|
||||
DBUtils.saveSummary( self, lock, smry );
|
||||
m_selGames.add( lock.getRowid() );
|
||||
lock.unlock();
|
||||
mkListAdapter();
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case R.id.games_game_reset:
|
||||
doConfirmReset( selRowIDs );
|
||||
break;
|
||||
|
||||
case R.id.games_game_rename:
|
||||
m_rowid = selRowIDs[0];
|
||||
showDialog( DlgID.RENAME_GAME );
|
||||
break;
|
||||
default:
|
||||
handled = false;
|
||||
}
|
||||
|
||||
if ( dropSels ) {
|
||||
clearSelections();
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
private boolean handleSelGroupsItem( int itemID, long[] groupIDs )
|
||||
{
|
||||
boolean handled = true;
|
||||
String msg;
|
||||
Assert.assertTrue( 0 < groupIDs.length );
|
||||
long groupID = groupIDs[0];
|
||||
switch( itemID ) {
|
||||
case R.id.games_group_delete:
|
||||
long dftGroup = XWPrefs.getDefaultNewGameGroup( m_activity );
|
||||
if ( m_selGroupIDs.contains( dftGroup ) ) {
|
||||
msg = getString( R.string.cannot_delete_default_group_fmt,
|
||||
m_adapter.groupName( dftGroup ) );
|
||||
showOKOnlyDialog( msg );
|
||||
} else {
|
||||
Assert.assertTrue( 0 < groupIDs.length );
|
||||
msg = getQuantityString( R.plurals.groups_confirm_del_fmt,
|
||||
groupIDs.length, groupIDs.length );
|
||||
|
||||
int nGames = 0;
|
||||
for ( long tmp : groupIDs ) {
|
||||
nGames += m_adapter.getChildrenCount( tmp );
|
||||
}
|
||||
if ( 0 < nGames ) {
|
||||
msg += getQuantityString( R.plurals.groups_confirm_del_games_fmt,
|
||||
nGames, nGames );
|
||||
}
|
||||
showConfirmThen( msg, Action.DELETE_GROUPS, groupIDs );
|
||||
}
|
||||
break;
|
||||
case R.id.games_group_default:
|
||||
XWPrefs.setDefaultNewGameGroup( m_activity, groupID );
|
||||
break;
|
||||
case R.id.games_group_rename:
|
||||
m_groupid = groupID;
|
||||
showDialog( DlgID.RENAME_GROUP );
|
||||
break;
|
||||
case R.id.games_group_moveup:
|
||||
moveGroup( groupID, true );
|
||||
break;
|
||||
case R.id.games_group_movedown:
|
||||
moveGroup( groupID, false );
|
||||
break;
|
||||
default:
|
||||
handled = false;
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
private void setupButtons()
|
||||
{
|
||||
boolean hidden = XWPrefs.getHideNewgameButtons( m_activity );
|
||||
|
@ -1741,7 +1911,7 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
long[] rowids = DBUtils.getRowIDsFor( m_activity, relayID );
|
||||
if ( null != rowids ) {
|
||||
for ( long rowid : rowids ) {
|
||||
m_adapter.reloadGame( rowid );
|
||||
reloadGame( rowid );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1848,33 +2018,44 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
// used to connect.
|
||||
private void startRematch( Intent intent )
|
||||
{
|
||||
if ( XWApp.REMATCH_SUPPORTED ) {
|
||||
long rowid = intent.getLongExtra( REMATCH_ROWID_EXTRA, -1 );
|
||||
if ( -1 != rowid ) {
|
||||
String btAddr = intent.getStringExtra( REMATCH_BTADDR_EXTRA );
|
||||
String phone = intent.getStringExtra( REMATCH_PHONE_EXTRA );
|
||||
String relayID = intent.getStringExtra( REMATCH_RELAYID_EXTRA );
|
||||
long newid;
|
||||
if ( null == btAddr && null == phone && null == relayID ) {
|
||||
// this will juggle if the preference is set
|
||||
newid = GameUtils.dupeGame( m_activity, rowid );
|
||||
} else {
|
||||
int bits = intent.getIntExtra( REMATCH_ADDRS_EXTRA, -1 );
|
||||
CommsConnTypeSet addrs = new CommsConnTypeSet( bits );
|
||||
|
||||
long groupID = DBUtils.getGroupForGame( m_activity, rowid );
|
||||
String gameName = "rematch"; // FIX ME :-)
|
||||
newid = GameUtils.makeNewMultiGame( m_activity, groupID,
|
||||
addrs, gameName );
|
||||
|
||||
DBUtils.addRematchInfo( m_activity, newid, btAddr, phone,
|
||||
relayID );
|
||||
}
|
||||
launchGame( newid );
|
||||
}
|
||||
if ( XWApp.REMATCH_SUPPORTED
|
||||
&& ( -1 != intent.getLongExtra( REMATCH_ROWID_EXTRA, -1 ) ) ) {
|
||||
m_rematchIntent = intent;
|
||||
showDialog( DlgID.GAMES_LIST_NAME_REMATCH );
|
||||
}
|
||||
}
|
||||
|
||||
private void startRematchWithName( EditText edit )
|
||||
{
|
||||
String gameName = edit.getText().toString();
|
||||
if ( null != gameName && 0 < gameName.length() ) {
|
||||
Intent intent = m_rematchIntent;
|
||||
long srcRowID = intent.getLongExtra( REMATCH_ROWID_EXTRA, -1 );
|
||||
String btAddr = intent.getStringExtra( REMATCH_BTADDR_EXTRA );
|
||||
String phone = intent.getStringExtra( REMATCH_PHONE_EXTRA );
|
||||
String relayID = intent.getStringExtra( REMATCH_RELAYID_EXTRA );
|
||||
String dict = intent.getStringExtra( REMATCH_DICT_EXTRA );
|
||||
int lang = intent.getIntExtra( REMATCH_LANG_EXTRA, -1 );
|
||||
int bits = intent.getIntExtra( REMATCH_ADDRS_EXTRA, -1 );
|
||||
CommsConnTypeSet addrs = new CommsConnTypeSet( bits );
|
||||
|
||||
long newid;
|
||||
if ( null == btAddr && null == phone && null == relayID ) {
|
||||
newid = GameUtils.dupeGame( m_activity, srcRowID );
|
||||
DBUtils.setName( m_activity, newid, gameName );
|
||||
} else {
|
||||
long groupID = DBUtils.getGroupForGame( m_activity, srcRowID );
|
||||
newid = GameUtils.makeNewMultiGame( m_activity, groupID,
|
||||
dict, lang,
|
||||
addrs, gameName );
|
||||
DBUtils.addRematchInfo( m_activity, newid, btAddr, phone,
|
||||
relayID );
|
||||
}
|
||||
launchGame( newid );
|
||||
}
|
||||
m_rematchIntent = null;
|
||||
}
|
||||
|
||||
private void tryAlert( Intent intent )
|
||||
{
|
||||
String msg = intent.getStringExtra( ALERT_MSG );
|
||||
|
@ -1894,16 +2075,11 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
}
|
||||
}
|
||||
|
||||
private boolean askDefaultNameIf()
|
||||
private void askDefaultName()
|
||||
{
|
||||
boolean showing =
|
||||
null == CommonPrefs.getDefaultPlayerName( m_activity, 0, false );
|
||||
if ( showing ) {
|
||||
String name = CommonPrefs.getDefaultPlayerName( m_activity, 0, true );
|
||||
CommonPrefs.setDefaultPlayerName( m_activity, name );
|
||||
showDialog( DlgID.GET_NAME );
|
||||
}
|
||||
return showing;
|
||||
String name = CommonPrefs.getDefaultPlayerName( m_activity, 0, true );
|
||||
CommonPrefs.setDefaultPlayerName( m_activity, name );
|
||||
showDialog( DlgID.GET_NAME );
|
||||
}
|
||||
|
||||
private void getDictForLangIf()
|
||||
|
@ -2185,7 +2361,9 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
m_adapter = new GameListAdapter();
|
||||
setListAdapterKeepScroll( m_adapter );
|
||||
|
||||
// ListView listview = getListView();
|
||||
ListView listView = getListView();
|
||||
m_activity.registerForContextMenu( listView );
|
||||
|
||||
// String field = CommonPrefs.getSummaryField( m_activity );
|
||||
// long[] positions = XWPrefs.getGroupPositions( m_activity );
|
||||
// GameListAdapter adapter =
|
||||
|
@ -2196,26 +2374,80 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
// return adapter;
|
||||
}
|
||||
|
||||
private void makeThenLaunchOrConfigure( EditText edit, boolean doConfigure )
|
||||
// Returns true if user has what looks like a default name and has not
|
||||
// said he wants us to stop bugging him about it.
|
||||
private boolean askingChangeName( EditText edit, boolean doConfigure )
|
||||
{
|
||||
String name = edit.getText().toString();
|
||||
long rowID;
|
||||
long groupID = 1 == m_selGroupIDs.size()
|
||||
? m_selGroupIDs.iterator().next() : DBUtils.GROUPID_UNSPEC;
|
||||
if ( m_nextIsSolo ) {
|
||||
rowID = GameUtils.saveNew( m_activity,
|
||||
new CurGameInfo( m_activity ),
|
||||
groupID, name );
|
||||
} else {
|
||||
rowID = GameUtils.makeNewMultiGame( m_activity, groupID, name );
|
||||
}
|
||||
boolean asking = false;
|
||||
boolean skipAsk = XWPrefs
|
||||
.getPrefsBoolean( m_activity, R.string.key_notagain_dfltname,
|
||||
false );
|
||||
if ( ! skipAsk ) {
|
||||
String name1 = CommonPrefs.getDefaultPlayerName( m_activity, 0,
|
||||
false );
|
||||
String name2 = CommonPrefs.getDefaultOriginalPlayerName( m_activity, 0 );
|
||||
if ( null == name1 || name1.equals( name2 ) ) {
|
||||
asking = true;
|
||||
|
||||
if ( doConfigure ) {
|
||||
// configure it
|
||||
GameConfigDelegate.editForResult( m_activity, CONFIG_GAME, rowID );
|
||||
} else {
|
||||
// launch it
|
||||
GameUtils.launchGame( m_activity, rowID );
|
||||
String msg = LocUtils
|
||||
.getString( m_activity, R.string.not_again_dfltname_fmt,
|
||||
name2 );
|
||||
|
||||
Runnable onChecked = new Runnable() {
|
||||
public void run() {
|
||||
XWPrefs
|
||||
.setPrefsBoolean( m_activity,
|
||||
R.string.key_notagain_dfltname,
|
||||
true );
|
||||
}
|
||||
};
|
||||
showConfirmThen( onChecked, msg, android.R.string.ok,
|
||||
R.string.button_later, Action.NEW_GAME_DFLT_NAME,
|
||||
edit, doConfigure );
|
||||
}
|
||||
}
|
||||
return asking;
|
||||
}
|
||||
|
||||
private boolean makeThenLaunchOrConfigure()
|
||||
{
|
||||
boolean handled = null != m_newGameParams;
|
||||
if ( handled ) {
|
||||
EditText edit = (EditText)m_newGameParams[0];
|
||||
boolean doConfigure = (Boolean)m_newGameParams[1];
|
||||
m_newGameParams = null;
|
||||
makeThenLaunchOrConfigure( edit, doConfigure, true );
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
private void makeThenLaunchOrConfigure( EditText edit, boolean doConfigure,
|
||||
boolean skipAsk )
|
||||
{
|
||||
if ( skipAsk || !askingChangeName( edit, doConfigure ) ) {
|
||||
String name = edit.getText().toString();
|
||||
long rowID;
|
||||
long groupID = 1 == m_selGroupIDs.size()
|
||||
? m_selGroupIDs.iterator().next() : DBUtils.GROUPID_UNSPEC;
|
||||
|
||||
// Ideally we'd check here whether user has set player name.
|
||||
|
||||
if ( m_nextIsSolo ) {
|
||||
rowID = GameUtils.saveNew( m_activity,
|
||||
new CurGameInfo( m_activity ),
|
||||
groupID, name );
|
||||
} else {
|
||||
rowID = GameUtils.makeNewMultiGame( m_activity, groupID, name );
|
||||
}
|
||||
|
||||
if ( doConfigure ) {
|
||||
// configure it
|
||||
GameConfigDelegate.editForResult( m_activity, RequestCode
|
||||
.CONFIG_GAME, rowID );
|
||||
} else {
|
||||
// launch it
|
||||
GameUtils.launchGame( m_activity, rowID );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2255,24 +2487,30 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
}
|
||||
|
||||
public static Intent makeRematchIntent( Context context, long rowid,
|
||||
String dict, int lang,
|
||||
CommsConnTypeSet addrTypes,
|
||||
String btAddr, String phone,
|
||||
String relayID )
|
||||
String relayID, String newName )
|
||||
{
|
||||
Intent intent = null;
|
||||
if ( XWApp.REMATCH_SUPPORTED ) {
|
||||
DbgUtils.logf( "makeRematchIntent(btAddr=%s; phone=%s)", btAddr, phone );
|
||||
intent = makeSelfIntent( context );
|
||||
intent.putExtra( REMATCH_ROWID_EXTRA, rowid );
|
||||
intent.putExtra( REMATCH_ADDRS_EXTRA, addrTypes.toInt() );
|
||||
if ( null != btAddr ) {
|
||||
intent.putExtra( REMATCH_BTADDR_EXTRA, btAddr );
|
||||
}
|
||||
if ( null != phone ) {
|
||||
intent.putExtra( REMATCH_PHONE_EXTRA, phone );
|
||||
}
|
||||
if ( null != relayID ) {
|
||||
intent.putExtra( REMATCH_RELAYID_EXTRA, relayID );
|
||||
intent.putExtra( REMATCH_DICT_EXTRA, dict );
|
||||
intent.putExtra( REMATCH_LANG_EXTRA, lang );
|
||||
intent.putExtra( REMATCH_NEWNAME_EXTRA, newName );
|
||||
|
||||
if ( null != addrTypes ) {
|
||||
intent.putExtra( REMATCH_ADDRS_EXTRA, addrTypes.toInt() ); // here
|
||||
if ( null != btAddr ) {
|
||||
intent.putExtra( REMATCH_BTADDR_EXTRA, btAddr );
|
||||
}
|
||||
if ( null != phone ) {
|
||||
intent.putExtra( REMATCH_PHONE_EXTRA, phone );
|
||||
}
|
||||
if ( null != relayID ) {
|
||||
intent.putExtra( REMATCH_RELAYID_EXTRA, relayID );
|
||||
}
|
||||
}
|
||||
}
|
||||
return intent;
|
||||
|
|
|
@ -20,11 +20,10 @@
|
|||
|
||||
package org.eehouse.android.xw4;
|
||||
|
||||
import android.app.ListActivity;
|
||||
import android.os.Bundle;
|
||||
import android.view.Window;
|
||||
|
||||
public abstract class InviteActivity extends XWListActivity {
|
||||
public abstract class InviteActivity extends XWActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate( Bundle savedInstanceState )
|
||||
|
|
|
@ -22,18 +22,20 @@ package org.eehouse.android.xw4;
|
|||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.app.ListActivity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
abstract class InviteDelegate extends ListDelegateBase
|
||||
implements View.OnClickListener {
|
||||
implements View.OnClickListener,
|
||||
ViewGroup.OnHierarchyChangeListener {
|
||||
|
||||
public static final String DEVS = "DEVS";
|
||||
public static final String COUNTS = "COUNTS";
|
||||
|
@ -44,8 +46,10 @@ abstract class InviteDelegate extends ListDelegateBase
|
|||
protected Button m_rescanButton;
|
||||
protected Button m_clearButton;
|
||||
private Activity m_activity;
|
||||
private ListView m_lv;
|
||||
private View m_ev;
|
||||
|
||||
public InviteDelegate( ListDelegator delegator, Bundle savedInstanceState,
|
||||
public InviteDelegate( Delegator delegator, Bundle savedInstanceState,
|
||||
int layoutID )
|
||||
{
|
||||
super( delegator, savedInstanceState, layoutID, R.menu.empty );
|
||||
|
@ -67,9 +71,19 @@ abstract class InviteDelegate extends ListDelegateBase
|
|||
TextView descView = (TextView)findViewById( desc_id );
|
||||
descView.setText( descTxt );
|
||||
|
||||
m_lv = (ListView)findViewById( android.R.id.list );
|
||||
m_ev = findViewById( android.R.id.empty );
|
||||
if ( null != m_lv && null != m_ev ) {
|
||||
m_lv.setOnHierarchyChangeListener( this );
|
||||
showEmptyIfEmpty();
|
||||
}
|
||||
|
||||
tryEnable();
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
// View.OnClickListener
|
||||
////////////////////////////////////////
|
||||
public void onClick( View view )
|
||||
{
|
||||
if ( m_okButton == view ) {
|
||||
|
@ -88,6 +102,24 @@ abstract class InviteDelegate extends ListDelegateBase
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
// ViewGroup.OnHierarchyChangeListener
|
||||
////////////////////////////////////////
|
||||
public void onChildViewAdded( View parent, View child )
|
||||
{
|
||||
showEmptyIfEmpty();
|
||||
}
|
||||
public void onChildViewRemoved( View parent, View child )
|
||||
{
|
||||
showEmptyIfEmpty();
|
||||
}
|
||||
|
||||
private void showEmptyIfEmpty()
|
||||
{
|
||||
m_ev.setVisibility( 0 == m_lv.getChildCount()
|
||||
? View.VISIBLE : View.GONE );
|
||||
}
|
||||
|
||||
abstract void tryEnable() ;
|
||||
abstract void listSelected( String[][] devsP, int[][] countsP );
|
||||
abstract void scan();
|
||||
|
|
|
@ -28,15 +28,15 @@ import android.widget.ListView;
|
|||
public class ListDelegateBase extends DelegateBase {
|
||||
|
||||
private Activity m_activity;
|
||||
private ListDelegator m_delegator;
|
||||
private Delegator m_delegator;
|
||||
|
||||
protected ListDelegateBase( ListDelegator delegator, Bundle savedInstanceState,
|
||||
protected ListDelegateBase( Delegator delegator, Bundle savedInstanceState,
|
||||
int layoutID )
|
||||
{
|
||||
this( delegator, savedInstanceState, layoutID, R.menu.empty );
|
||||
}
|
||||
|
||||
protected ListDelegateBase( ListDelegator delegator, Bundle savedInstanceState,
|
||||
protected ListDelegateBase( Delegator delegator, Bundle savedInstanceState,
|
||||
int layoutID, int menuID )
|
||||
{
|
||||
super( delegator, savedInstanceState, layoutID, menuID );
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
package org.eehouse.android.xw4;
|
||||
|
||||
import android.content.Context;
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
|
@ -32,7 +32,9 @@ import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
|
|||
public class MultiMsgSink implements TransportProcs {
|
||||
private long m_rowid;
|
||||
private Context m_context;
|
||||
private int m_nSent = 0;
|
||||
// Use set to count so message sent over both BT and Relay is counted only
|
||||
// once.
|
||||
private Set<String> m_sentSet = new HashSet<String>();
|
||||
|
||||
public MultiMsgSink( Context context, long rowid )
|
||||
{
|
||||
|
@ -60,7 +62,7 @@ public class MultiMsgSink implements TransportProcs {
|
|||
|
||||
public int sendViaBluetooth( byte[] buf, int gameID, CommsAddrRec addr )
|
||||
{
|
||||
return BTService.enqueueFor( m_context, buf, addr.bt_btAddr, gameID );
|
||||
return BTService.enqueueFor( m_context, buf, addr, gameID );
|
||||
}
|
||||
|
||||
public int sendViaSMS( byte[] buf, int gameID, CommsAddrRec addr )
|
||||
|
@ -70,15 +72,15 @@ public class MultiMsgSink implements TransportProcs {
|
|||
|
||||
public int numSent()
|
||||
{
|
||||
return m_nSent;
|
||||
return m_sentSet.size();
|
||||
}
|
||||
|
||||
/***** TransportProcs interface *****/
|
||||
|
||||
public int getFlags() { return COMMS_XPORT_FLAGS_HASNOCONN; }
|
||||
|
||||
public int transportSend( byte[] buf, CommsAddrRec addr, CommsConnType typ,
|
||||
int gameID )
|
||||
public int transportSend( byte[] buf, String msgNo, CommsAddrRec addr,
|
||||
CommsConnType typ, int gameID )
|
||||
{
|
||||
int nSent = -1;
|
||||
switch ( typ ) {
|
||||
|
@ -97,6 +99,10 @@ public class MultiMsgSink implements TransportProcs {
|
|||
}
|
||||
DbgUtils.logf( "MultiMsgSink.transportSend(): sent %d via %s",
|
||||
nSent, typ.toString() );
|
||||
if ( 0 < nSent ) {
|
||||
DbgUtils.logdf( "MultiMsgSink.transportSend: adding %s", msgNo );
|
||||
m_sentSet.add( msgNo );
|
||||
}
|
||||
|
||||
return nSent;
|
||||
}
|
||||
|
@ -114,11 +120,16 @@ public class MultiMsgSink implements TransportProcs {
|
|||
{
|
||||
}
|
||||
|
||||
public boolean relayNoConnProc( byte[] buf, String relayID )
|
||||
public boolean relayNoConnProc( byte[] buf, String msgNo, String relayID )
|
||||
{
|
||||
// Assert.fail();
|
||||
int nSent = RelayService.sendNoConnPacket( m_context, getRowID(),
|
||||
relayID, buf );
|
||||
return buf.length == nSent;
|
||||
boolean success = buf.length == nSent;
|
||||
if ( success ) {
|
||||
DbgUtils.logdf( "MultiMsgSink.relayNoConnProc: adding %s", msgNo );
|
||||
m_sentSet.add( msgNo );
|
||||
}
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue