mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-20 22:26:54 +01:00
Merge remote-tracking branch 'origin/android_translate' into android_translate
This commit is contained in:
commit
b14c6b5003
112 changed files with 3559 additions and 2192 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -7,3 +7,4 @@ core*
|
|||
*.apk
|
||||
xwords_4.4.0.0*
|
||||
gcm_loop.shelf
|
||||
nohup.out
|
||||
|
|
|
@ -1,20 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- -*- compile-command: "ant install"; -*- -->
|
||||
<!-- Copyright (C) 2007 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<!-- Declare the contents of this Android application. The namespace
|
||||
attribute brings in the Android platform namespace, and the package
|
||||
supplies a unique name for the application. When writing your
|
||||
|
@ -22,14 +6,14 @@
|
|||
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="99"
|
||||
android:versionCode="100"
|
||||
android:versionName="@string/app_version"
|
||||
>
|
||||
|
||||
<!-- BE SURE TO MODIFY project.project AND the variable TARGET in
|
||||
<!-- BE SURE TO MODIFY project.properties AND the variable TARGET in
|
||||
../scripts/setup_local_props.sh if targetSdkVersion changes!!!
|
||||
-->
|
||||
<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="14" />
|
||||
<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="19" />
|
||||
|
||||
<supports-screens android:resizeable="true"
|
||||
android:smallScreens="true"
|
||||
|
@ -73,7 +57,7 @@
|
|||
android:debuggable="true"
|
||||
>
|
||||
|
||||
<activity android:name="GamesListActivity"
|
||||
<activity android:name="Main"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="standard"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
|
@ -88,25 +72,31 @@
|
|||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="@string/xwords_nfc_mime" />
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
<activity android:name="FragActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
/>
|
||||
<activity android:name="GamesListActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
/>
|
||||
|
||||
<activity android:name="DictsActivity"
|
||||
android:label="@string/title_dicts_list"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
/>
|
||||
|
||||
<activity android:name="BTInviteActivity"
|
||||
android:label="@string/bt_invite_title"
|
||||
android:label="@string/bt_invite_title"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
/>
|
||||
<activity android:name="SMSInviteActivity"
|
||||
android:label="@string/sms_invite_title"
|
||||
android:label="@string/sms_invite_title"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
android:screenOrientation="sensor"
|
||||
/>
|
||||
<activity android:name="RelayInviteActivity"
|
||||
android:label="@string/relay_invite_title"
|
||||
android:label="@string/relay_invite_title"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
/>
|
||||
|
||||
|
@ -224,10 +214,10 @@
|
|||
|
||||
<receiver android:name="BTReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.bluetooth.adapter.action.STATE_CHANGED" />
|
||||
<action android:name="android.bluetooth.device.action.ACL_CONNECTED" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.bluetooth.device.action.ACL_CONNECTED" />
|
||||
<action android:name="android.bluetooth.adapter.action.STATE_CHANGED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
|
|
1
xwords4/android/XWords4-dbg/libs/.gitignore
vendored
1
xwords4/android/XWords4-dbg/libs/.gitignore
vendored
|
@ -1,3 +1,4 @@
|
|||
gcm.jar
|
||||
armeabi
|
||||
x86
|
||||
android-support-v13.jar
|
||||
|
|
Binary file not shown.
BIN
xwords4/android/XWords4-dbg/libs/crittercism_v5_5_5_sdkonly.jar
Normal file
BIN
xwords4/android/XWords4-dbg/libs/crittercism_v5_5_5_sdkonly.jar
Normal file
Binary file not shown.
|
@ -8,4 +8,4 @@
|
|||
# project structure.
|
||||
|
||||
# Project target.
|
||||
target=android-14
|
||||
target=android-19
|
||||
|
|
|
@ -27,3 +27,4 @@ in_arrow_active.png
|
|||
in_arrow.png
|
||||
out_arrow_active.png
|
||||
out_arrow.png
|
||||
notify.png
|
||||
|
|
|
@ -44,3 +44,6 @@ not_again_view.xml
|
|||
relayinviter.xml
|
||||
remote_dict_details.xml
|
||||
toolbar.xml
|
||||
chat_row.xml
|
||||
fragact.xml
|
||||
main.xml
|
||||
|
|
|
@ -125,3 +125,13 @@ XWConnAddrPreference.java
|
|||
XWDevIDPreference.java
|
||||
XWExpListAdapter.java
|
||||
RequestCode.java
|
||||
BoardFrag.java
|
||||
ChatFrag.java
|
||||
DictBrowseFrag.java
|
||||
FragActivity.java
|
||||
GameConfigFrag.java
|
||||
GamesListFrag.java
|
||||
Main.java
|
||||
nohup.out
|
||||
StudyListFrag.java
|
||||
XWFragment.java
|
||||
|
|
3
xwords4/android/XWords4/.gitignore
vendored
3
xwords4/android/XWords4/.gitignore
vendored
|
@ -13,7 +13,8 @@
|
|||
ant_out.txt
|
||||
bin
|
||||
gen
|
||||
local.properties
|
||||
obj
|
||||
proguard.cfg
|
||||
res/drawable*/*gen.png
|
||||
.idea/
|
||||
*.iml
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
XWords4
|
|
@ -1,229 +0,0 @@
|
|||
<?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_LEGACY_SETTINGS_IMPORTED" 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>Namespace:</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:.*</NAME>
|
||||
<XML_NAMESPACE>Namespace:</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>
|
|
@ -1,22 +0,0 @@
|
|||
<?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>
|
|
@ -1,3 +0,0 @@
|
|||
<component name="CopyrightManager">
|
||||
<settings default="" />
|
||||
</component>
|
|
@ -1,18 +0,0 @@
|
|||
<?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>
|
|
@ -1,62 +0,0 @@
|
|||
<?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>
|
|
@ -1,9 +0,0 @@
|
|||
<?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>
|
|
@ -1,12 +0,0 @@
|
|||
<?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>
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/../../.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
|
@ -22,14 +22,14 @@
|
|||
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="99"
|
||||
android:versionCode="101"
|
||||
android:versionName="@string/app_version"
|
||||
>
|
||||
|
||||
<!-- BE SURE TO MODIFY project.project AND the variable TARGET in
|
||||
../scripts/setup_local_props.sh if targetSdkVersion changes!!!
|
||||
-->
|
||||
<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="14" />
|
||||
<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="19" />
|
||||
|
||||
<supports-screens android:resizeable="true"
|
||||
android:smallScreens="true"
|
||||
|
@ -69,7 +69,7 @@
|
|||
android:name=".XWApp"
|
||||
>
|
||||
|
||||
<activity android:name="GamesListActivity"
|
||||
<activity android:name="Main"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="standard"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
|
@ -84,9 +84,15 @@
|
|||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="@string/xwords_nfc_mime" />
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
<activity android:name="FragActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
/>
|
||||
<activity android:name="GamesListActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
/>
|
||||
|
||||
<activity android:name="DictsActivity"
|
||||
android:label="@string/title_dicts_list"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
<?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,86 +0,0 @@
|
|||
<?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/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/manifests" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
|
||||
<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/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>
|
|
@ -12,6 +12,7 @@ apply plugin: 'com.android.application'
|
|||
|
||||
dependencies {
|
||||
compile files('../libs/gcm.jar')
|
||||
compile files('../libs/android-support-v13.jar')
|
||||
}
|
||||
|
||||
android {
|
||||
|
@ -19,7 +20,7 @@ android {
|
|||
buildToolsVersion "22.0.1"
|
||||
defaultConfig {
|
||||
minSdkVersion 7
|
||||
targetSdkVersion 14
|
||||
targetSdkVersion 19
|
||||
}
|
||||
|
||||
// Rename all output artifacts to include version information
|
||||
|
@ -103,6 +104,27 @@ android {
|
|||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
|
||||
def gitrev = "git describe --tags".execute().text
|
||||
applicationVariants.all { variant ->
|
||||
variant.outputs.each { output ->
|
||||
output.outputFile =
|
||||
new File(output.outputFile.parent,
|
||||
output.outputFile.name.replace(".apk", "-${gitrev}.apk"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent release builds. They haven't been tested, and now that
|
||||
// f-droid has been releasing them they're KNOWN not to work.
|
||||
android.applicationVariants.all { variant ->
|
||||
if ( variant.name.endsWith("Release") ) {
|
||||
String NAME = "check" + variant.name.capitalize() + "Manifest"
|
||||
task "$NAME"(overwrite: true) << {
|
||||
throw new RuntimeException('<<<<< Release builds should not be built '
|
||||
+ 'using gradle! Please use ant for now. >>>>>');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -13,10 +13,10 @@
|
|||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Crosswords 4.4.105 release</h2>
|
||||
<h2>Crosswords 4.4.107 release</h2>
|
||||
|
||||
<p>This release fixes a problem with rematches not preserving game
|
||||
settings like "Allow hints."</p>
|
||||
<p>This version, for F-droid release only, fixes build problems that
|
||||
caused a number of crashes and other issues.</p>
|
||||
|
||||
<div id="survey">
|
||||
<p>Please <a href="https://www.surveymonkey.com/s/GX3XLHR">take
|
||||
|
@ -26,11 +26,7 @@
|
|||
|
||||
<h3>New with this release</h3>
|
||||
<ul>
|
||||
<li>When creating a game to rematch, preserve the original's
|
||||
settings for hints, board size, timer and phonies</li>
|
||||
<li>Fix tiles left of tray divider sometimes being included in hints</li>
|
||||
<li>Unless "View tiles out-of-turn" is enabled, show summary of
|
||||
last move when scoreboard entry is tapped</li>
|
||||
<li>Force release builds to be done with ant rather than gradle</li>
|
||||
</ul>
|
||||
|
||||
<p>(The full changelog
|
||||
|
@ -38,6 +34,8 @@
|
|||
|
||||
<h3>Next up</h3>
|
||||
<ul>
|
||||
<li>More chat improvements, especially allowing to send and
|
||||
receive without closing the chat window</li>
|
||||
<li>Take advantage of Marshmallow's new permissions model (where
|
||||
the app only asks for them when it needs them.)
|
||||
</ul>
|
||||
|
|
|
@ -5,7 +5,7 @@ buildscript {
|
|||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:1.3.0'
|
||||
classpath 'com.android.tools.build:gradle:2.1.0'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
|
@ -26,7 +26,7 @@ subprojects {
|
|||
afterEvaluate {project ->
|
||||
if (project.hasProperty("android")) {
|
||||
android {
|
||||
compileSdkVersion 14
|
||||
compileSdkVersion 19
|
||||
buildToolsVersion '22.0.1'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#Mon Nov 09 19:22:17 PST 2015
|
||||
#Thu Apr 07 12:32:10 PDT 2016
|
||||
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
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
|
||||
|
|
|
@ -250,12 +250,13 @@ and_util_turnChanged( XW_UtilCtxt* uc, XP_S16 turn )
|
|||
#endif
|
||||
|
||||
static void
|
||||
and_util_informMove( XW_UtilCtxt* uc, XWStreamCtxt* expl, XWStreamCtxt* words )
|
||||
and_util_informMove( XW_UtilCtxt* uc, XP_S16 turn, XWStreamCtxt* expl,
|
||||
XWStreamCtxt* words )
|
||||
{
|
||||
UTIL_CBK_HEADER( "informMove", "(Ljava/lang/String;Ljava/lang/String;)V" );
|
||||
UTIL_CBK_HEADER( "informMove", "(ILjava/lang/String;Ljava/lang/String;)V" );
|
||||
jstring jexpl = streamToJString( env, expl );
|
||||
jstring jwords = !!words ? streamToJString( env, words ) : NULL;
|
||||
(*env)->CallVoidMethod( env, util->jutil, mid, jexpl, jwords );
|
||||
(*env)->CallVoidMethod( env, util->jutil, mid, turn, jexpl, jwords );
|
||||
deleteLocalRefs( env, jexpl, jwords, DELETE_NO_REF );
|
||||
UTIL_CBK_TAIL();
|
||||
}
|
||||
|
@ -503,7 +504,7 @@ and_util_warnIllegalWord( XW_UtilCtxt* uc, BadWordInfo* bwi,
|
|||
static void
|
||||
and_util_showChat( XW_UtilCtxt* uc, const XP_UCHAR const* msg, XP_S16 from )
|
||||
{
|
||||
UTIL_CBK_HEADER( "showChat", "(Ljava/lang/String;Ljava/lang/String;)V" );
|
||||
UTIL_CBK_HEADER( "showChat", "(Ljava/lang/String;ILjava/lang/String;)V" );
|
||||
jstring jname = NULL;
|
||||
if ( 0 <= from ) {
|
||||
LocalPlayer* lp = &uc->gameInfo->players[from];
|
||||
|
@ -512,7 +513,7 @@ and_util_showChat( XW_UtilCtxt* uc, const XP_UCHAR const* msg, XP_S16 from )
|
|||
}
|
||||
|
||||
jstring jmsg = (*env)->NewStringUTF( env, msg );
|
||||
(*env)->CallVoidMethod( env, util->jutil, mid, jmsg, jname );
|
||||
(*env)->CallVoidMethod( env, util->jutil, mid, jmsg, from, jname );
|
||||
deleteLocalRefs( env, jmsg, jname, DELETE_NO_REF );
|
||||
UTIL_CBK_TAIL();
|
||||
}
|
||||
|
|
|
@ -748,10 +748,10 @@ Java_org_eehouse_android_xw4_jni_XwJNI_envDone
|
|||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeNewGame
|
||||
( JNIEnv* env, jclass C, GamePtrType gamePtr, jobject j_gi, jobject j_util,
|
||||
jobject jniu, jobject j_draw, jobject j_cp, jobject j_procs,
|
||||
( JNIEnv* env, jclass C, GamePtrType gamePtr, jobject j_gi,
|
||||
jobjectArray j_names, jobjectArray j_dicts, jobjectArray j_paths,
|
||||
jstring j_lang )
|
||||
jstring j_lang, jobject j_util, jobject jniu, jobject j_draw,
|
||||
jobject j_cp, jobject j_procs )
|
||||
{
|
||||
XWJNI_START_GLOBALS();
|
||||
EnvThreadInfo* ti = &state->globalJNI->ti;
|
||||
|
@ -1127,6 +1127,17 @@ Java_org_eehouse_android_xw4_jni_XwJNI_board_1getTrayVisState
|
|||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_board_1getSelPlayer
|
||||
(JNIEnv* env, jclass C, GamePtrType gamePtr)
|
||||
{
|
||||
jint result;
|
||||
XWJNI_START();
|
||||
result = board_getSelPlayer( state->game.board );
|
||||
XWJNI_END();
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_board_1hideTray
|
||||
(JNIEnv* env, jclass C, GamePtrType gamePtr)
|
||||
|
|
BIN
xwords4/android/XWords4/libs/android-support-v13.jar
Normal file
BIN
xwords4/android/XWords4/libs/android-support-v13.jar
Normal file
Binary file not shown.
|
@ -11,4 +11,4 @@
|
|||
# proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||
|
||||
# Project target.
|
||||
target=android-14
|
||||
target=android-19
|
||||
|
|
|
@ -6,27 +6,28 @@
|
|||
android:layout_height="fill_parent"
|
||||
>
|
||||
|
||||
<!-- history is kept in a scrolling list of textview elems so
|
||||
different style can be applied based on whether they're local or
|
||||
remote. Inserted at runtime.... -->
|
||||
<ScrollView android:id="@+id/scroll"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
>
|
||||
<LinearLayout android:id="@+id/chat_history"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
/>
|
||||
|
||||
<!-- contents inserted at runtime -->
|
||||
<TableLayout android:id="@+id/chat_history"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
/>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
<EditText android:id="@+id/chat_edit"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="false"
|
||||
android:inputType="textCapSentences"
|
||||
android:layout_weight="0"
|
||||
android:hint="@string/chat_hint"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
/>
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#FF202020"
|
||||
/>
|
16
xwords4/android/XWords4/res/layout/chat_row.xml
Normal file
16
xwords4/android/XWords4/res/layout/chat_row.xml
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<TableRow xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<TextView android:id="@+id/chat_row_name"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:layout_marginRight="8dp"
|
||||
/>
|
||||
<TextView android:id="@+id/chat_row_text"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:singleLine="false"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
/>
|
||||
</TableRow>
|
8
xwords4/android/XWords4/res/layout/fragact.xml
Normal file
8
xwords4/android/XWords4/res/layout/fragact.xml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/main_container"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
/>
|
26
xwords4/android/XWords4/res/layout/main.xml
Normal file
26
xwords4/android/XWords4/res/layout/main.xml
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:background="#FF000007"
|
||||
>
|
||||
<!-- probably want some explanatory text here -->
|
||||
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#FF000000"
|
||||
>
|
||||
<Button android:id="@+id/activity_button"
|
||||
android:text="@string/activity_button"
|
||||
style="@style/evenly_spaced_horizontal"
|
||||
/>
|
||||
<Button android:id="@+id/fragment_button"
|
||||
android:text="@string/fragment_button"
|
||||
style="@style/evenly_spaced_horizontal"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<resources>
|
||||
<string name="app_version">4.4.105</string>
|
||||
<string name="app_version">4.4.107</string>
|
||||
</resources>
|
||||
|
|
|
@ -1291,6 +1291,8 @@
|
|||
<!-- Text on the button that causes the contents of the
|
||||
message-composition field to be sent. -->
|
||||
<string name="chat_send">Send</string>
|
||||
<!-- "Hint" in empty chat text field -->
|
||||
<string name="chat_hint">Type here...</string>
|
||||
|
||||
<!--
|
||||
############################################################
|
||||
|
@ -2020,6 +2022,7 @@
|
|||
<string name="menu_zoom">Zoom in/out</string>
|
||||
<!-- -->
|
||||
<string name="menu_chat">Chat</string>
|
||||
<string name="chat_sender_fmt">%1$s:</string>
|
||||
<!-- -->
|
||||
<string name="menu_toggle_values">Toggle values</string>
|
||||
|
||||
|
@ -2029,6 +2032,8 @@
|
|||
<!-- -->
|
||||
<string name="game_list_tmp">Building game summary…</string>
|
||||
|
||||
<string name="summary_busy">Summary unavailable</string>
|
||||
|
||||
<string name="connstat_net_noaddr">This networked game has no way
|
||||
to connect and will never be playable.\n\n(It was probably created
|
||||
from an invitation that didn\'t specify any way of connecting
|
||||
|
@ -2367,6 +2372,9 @@
|
|||
<string name="force_tablet_title">Force tablet layout</string>
|
||||
<string name="force_tablet_summary">Even if my screen is too small</string>
|
||||
|
||||
<string name="activity_button">Single-pane</string>
|
||||
<string name="fragment_button">Dual-pane</string>
|
||||
|
||||
<!-- Nagging: title of notification reminder message -->
|
||||
<string name="nag_title">Reminder: It\'s your turn</string>
|
||||
<!-- body of warning notification reminder message. First three
|
||||
|
@ -2407,9 +2415,10 @@
|
|||
devices. Would you like to open the Android Settings Panel to add
|
||||
one or more?\n\n(You may also need to open it on the device you
|
||||
want to pair with.)</string>
|
||||
<string name="app_not_found_fmt">Unable to connect to Crosswords
|
||||
on the device %1$s. Please check that the device is within range
|
||||
and that Crosswords is installed on it.</string>
|
||||
<string name="app_not_found_fmt">Unable to connect via Bluetooth
|
||||
to Crosswords on the device %1$s. Please check that the device is
|
||||
within Bluetooth range and that Crosswords is installed on
|
||||
it.</string>
|
||||
|
||||
<!-- label within default wordlists in app preferences -->
|
||||
<string name="default_language">Default language</string>
|
||||
|
|
|
@ -90,6 +90,12 @@
|
|||
<item name="android:layout_weight">1</item>
|
||||
</style>
|
||||
|
||||
<!-- <style name="spaced_buttons"> -->
|
||||
<!-- <item name="android:layout_width">fill_parent</item> -->
|
||||
<!-- <item name="android:layout_height">wrap_content</item> -->
|
||||
<!-- <item name="android:layout_weight">1</item> -->
|
||||
<!-- </style> -->
|
||||
|
||||
<style name="newgame_connicon">
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
|
|
|
@ -1116,6 +1116,8 @@
|
|||
<!-- Text on the button that causes the contents of the
|
||||
message-composition field to be sent. -->
|
||||
<string name="chat_send">Dnes</string>
|
||||
<!-- "Hint" in empty chat text field -->
|
||||
<string name="chat_hint">Epyt ereh...</string>
|
||||
<!--
|
||||
############################################################
|
||||
# :Menus:
|
||||
|
@ -1747,12 +1749,14 @@
|
|||
<string name="menu_zoom">Mooz tuo/ni</string>
|
||||
<!-- -->
|
||||
<string name="menu_chat">Tahc</string>
|
||||
<string name="chat_sender_fmt">%1$s:</string>
|
||||
<!-- -->
|
||||
<string name="menu_toggle_values">Elggot seulav</string>
|
||||
<!-- board menu for small devices only -->
|
||||
<string name="board_menu_dict">Esworb tsildrow</string>
|
||||
<!-- -->
|
||||
<string name="game_list_tmp">Gnidliub emag yrammus…</string>
|
||||
<string name="summary_busy">Yrammus elbaliavanu</string>
|
||||
<string name="connstat_net_noaddr">Siht dekrowten emag sah on yaw
|
||||
ot tcennoc dna lliw reven eb elbayalp.\n\ntI( saw ylbaborp detaerc
|
||||
morf na noitativni taht ndid\'t yficeps yna yaw fo gnitcennoc
|
||||
|
@ -2032,6 +2036,8 @@
|
|||
tahw\'s elbaliava.</string>
|
||||
<string name="force_tablet_title">Ecrof telbat tuoyal</string>
|
||||
<string name="force_tablet_summary">Neve fi ym neercs si oot llams</string>
|
||||
<string name="activity_button">Enap-elgnis</string>
|
||||
<string name="fragment_button">Enap-laud</string>
|
||||
<!-- Nagging: title of notification reminder message -->
|
||||
<string name="nag_title">Rednimer: Ti\'s ruoy nrut</string>
|
||||
<!-- body of warning notification reminder message. First three
|
||||
|
|
|
@ -1116,6 +1116,8 @@
|
|||
<!-- Text on the button that causes the contents of the
|
||||
message-composition field to be sent. -->
|
||||
<string name="chat_send">SEND</string>
|
||||
<!-- "Hint" in empty chat text field -->
|
||||
<string name="chat_hint">TYPE HERE...</string>
|
||||
<!--
|
||||
############################################################
|
||||
# :Menus:
|
||||
|
@ -1747,12 +1749,14 @@
|
|||
<string name="menu_zoom">ZOOM IN/OUT</string>
|
||||
<!-- -->
|
||||
<string name="menu_chat">CHAT</string>
|
||||
<string name="chat_sender_fmt">%1$s:</string>
|
||||
<!-- -->
|
||||
<string name="menu_toggle_values">TOGGLE VALUES</string>
|
||||
<!-- board menu for small devices only -->
|
||||
<string name="board_menu_dict">BROWSE WORDLIST</string>
|
||||
<!-- -->
|
||||
<string name="game_list_tmp">BUILDING GAME SUMMARY…</string>
|
||||
<string name="summary_busy">SUMMARY UNAVAILABLE</string>
|
||||
<string name="connstat_net_noaddr">THIS NETWORKED GAME HAS NO WAY
|
||||
TO CONNECT AND WILL NEVER BE PLAYABLE.\n\n(IT WAS PROBABLY CREATED
|
||||
FROM AN INVITATION THAT DIDN\'T SPECIFY ANY WAY OF CONNECTING
|
||||
|
@ -2032,6 +2036,8 @@
|
|||
WHAT\'S AVAILABLE.</string>
|
||||
<string name="force_tablet_title">FORCE TABLET LAYOUT</string>
|
||||
<string name="force_tablet_summary">EVEN IF MY SCREEN IS TOO SMALL</string>
|
||||
<string name="activity_button">SINGLE-PANE</string>
|
||||
<string name="fragment_button">DUAL-PANE</string>
|
||||
<!-- Nagging: title of notification reminder message -->
|
||||
<string name="nag_title">REMINDER: IT\'S YOUR TURN</string>
|
||||
<!-- body of warning notification reminder message. First three
|
||||
|
|
|
@ -237,14 +237,6 @@ public class BTInviteDelegate extends InviteDelegate {
|
|||
public void onCheckedChanged( CompoundButton buttonView,
|
||||
boolean isChecked ) {
|
||||
if ( isChecked ) {
|
||||
if ( 1 == m_nMissing && 1 == m_checked.size() ) {
|
||||
LinearLayout checked = m_checked.iterator().next();
|
||||
CheckBox box = (CheckBox)checked
|
||||
.findViewById( R.id.inviter_check );
|
||||
box.setChecked( false );
|
||||
m_checked.clear();
|
||||
}
|
||||
|
||||
m_checked.add( layout );
|
||||
} else {
|
||||
m_checked.remove( layout );
|
||||
|
|
|
@ -53,7 +53,9 @@ 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.jni.JNIThread;
|
||||
import org.eehouse.android.xw4.loc.LocUtils;
|
||||
import org.eehouse.android.xw4.XWService.ReceiveResult;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
|
@ -573,44 +575,20 @@ public class BTService extends XWService {
|
|||
BluetoothDevice host = socket.getRemoteDevice();
|
||||
addAddr( host );
|
||||
|
||||
// check if still here
|
||||
long[] rowids = DBUtils.getRowIDsFor( BTService.this,
|
||||
gameID );
|
||||
boolean haveGame = null != rowids && 0 < rowids.length;
|
||||
BTCmd result = haveGame ?
|
||||
BTCmd.MESG_ACCPT : BTCmd.MESG_GAMEGONE;
|
||||
CommsAddrRec addr = new CommsAddrRec( host.getName(),
|
||||
host.getAddress() );
|
||||
ReceiveResult rslt
|
||||
= BTService.this.receiveMessage( BTService.this, gameID,
|
||||
m_btMsgSink, buffer, addr );
|
||||
|
||||
BTCmd result = rslt == ReceiveResult.GAME_GONE ?
|
||||
BTCmd.MESG_GAMEGONE : BTCmd.MESG_ACCPT;
|
||||
|
||||
DataOutputStream os =
|
||||
new DataOutputStream( socket.getOutputStream() );
|
||||
os.writeByte( result.ordinal() );
|
||||
os.flush();
|
||||
socket.close();
|
||||
|
||||
CommsAddrRec addr = new CommsAddrRec( host.getName(),
|
||||
host.getAddress() );
|
||||
|
||||
boolean[] isLocalP = new boolean[1];
|
||||
for ( long rowid : rowids ) {
|
||||
boolean consumed =
|
||||
BoardDelegate.feedMessage( rowid, buffer, addr );
|
||||
if ( !consumed && haveGame ) {
|
||||
GameUtils.BackMoveResult bmr =
|
||||
new GameUtils.BackMoveResult();
|
||||
if ( GameUtils.feedMessage( BTService.this, rowid,
|
||||
buffer, addr,
|
||||
m_btMsgSink, bmr,
|
||||
isLocalP ) ) {
|
||||
consumed = true;
|
||||
GameUtils.postMoveNotification( BTService.this,
|
||||
rowid, bmr,
|
||||
isLocalP[0] );
|
||||
}
|
||||
}
|
||||
if ( !consumed ) {
|
||||
DbgUtils.logf( "nobody took msg for gameID %X",
|
||||
gameID );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DbgUtils.logf( "receiveMessages: read only %d of %d bytes",
|
||||
nRead, len );
|
||||
|
@ -850,7 +828,7 @@ public class BTService extends XWService {
|
|||
}
|
||||
|
||||
if ( null == reply ) {
|
||||
sendResult( MultiEvent.APP_NOT_FOUND, dev.getName() );
|
||||
sendResult( MultiEvent.APP_NOT_FOUND_BT, dev.getName() );
|
||||
} else {
|
||||
switch ( reply ) {
|
||||
case BAD_PROTO:
|
||||
|
@ -1015,7 +993,8 @@ public class BTService extends XWService {
|
|||
synchronized( m_addrs ) {
|
||||
for ( BluetoothDevice dev : pairedDevs ) {
|
||||
int clazz = dev.getBluetoothClass().getMajorDeviceClass();
|
||||
if ( Major.PHONE == clazz || Major.COMPUTER == clazz ) {
|
||||
if ( Major.PHONE == clazz
|
||||
|| (XWApp.BT_SCAN_COMPUTERS && Major.COMPUTER == clazz) ) {
|
||||
m_addrs.add( dev.getAddress() );
|
||||
}
|
||||
}
|
||||
|
@ -1186,6 +1165,9 @@ public class BTService extends XWService {
|
|||
|
||||
private void updateStatusOut( boolean success )
|
||||
{
|
||||
// Intent intent = GamesListDelegate.makeGameIDIntent( this, gameID );
|
||||
// Utils.postNotification( this, intent, R.string.new_btmove_title,
|
||||
// body, (int)rowid );
|
||||
ConnStatusHandler
|
||||
.updateStatusOut( this, null, CommsConnType.COMMS_CONN_BT, success );
|
||||
}
|
||||
|
|
|
@ -89,7 +89,6 @@ public class BoardDelegate extends DelegateBase
|
|||
private CurGameInfo m_gi;
|
||||
private GameSummary m_summary;
|
||||
private boolean m_relayMissing;
|
||||
private CommsTransport m_xport;
|
||||
private Handler m_handler = null;
|
||||
private TimerRunnable[] m_timers;
|
||||
private Runnable m_screenTimer;
|
||||
|
@ -128,6 +127,7 @@ public class BoardDelegate extends DelegateBase
|
|||
|
||||
private Thread m_blockingThread;
|
||||
private JNIThread m_jniThread;
|
||||
private JNIThread m_jniThreadRef;
|
||||
private JNIThread.GameStateInfo m_gsi;
|
||||
private DlgID m_blockingDlgID = DlgID.NONE;
|
||||
|
||||
|
@ -142,57 +142,6 @@ public class BoardDelegate extends DelegateBase
|
|||
private boolean m_haveInvited = false;
|
||||
private boolean m_overNotShown;
|
||||
|
||||
private static Set<BoardDelegate> s_this = new HashSet<BoardDelegate>();
|
||||
|
||||
public static boolean feedMessage( long rowid, byte[] msg,
|
||||
CommsAddrRec ret )
|
||||
{
|
||||
return feedMessages( rowid, new byte[][]{msg}, ret );
|
||||
}
|
||||
|
||||
public static boolean feedMessages( long rowid, byte[][] msgs,
|
||||
CommsAddrRec ret )
|
||||
{
|
||||
boolean delivered = false;
|
||||
Assert.assertNotNull( msgs );
|
||||
int size;
|
||||
synchronized( s_this ) {
|
||||
size = s_this.size();
|
||||
if ( 1 == size ) {
|
||||
BoardDelegate self = s_this.iterator().next();
|
||||
Assert.assertNotNull( self.m_gi );
|
||||
Assert.assertNotNull( self.m_gameLock );
|
||||
Assert.assertNotNull( self.m_jniThread );
|
||||
if ( rowid == self.m_rowid ) {
|
||||
delivered = true; // even if no messages!
|
||||
for ( byte[] msg : msgs ) {
|
||||
self.m_jniThread.handle( JNICmd.CMD_RECEIVE, msg, ret );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( 1 < size ) {
|
||||
noteSkip();
|
||||
}
|
||||
return delivered;
|
||||
}
|
||||
|
||||
private static void setThis( BoardDelegate self )
|
||||
{
|
||||
synchronized( s_this ) {
|
||||
Assert.assertTrue( !s_this.contains(self) ); // here
|
||||
s_this.add( self );
|
||||
}
|
||||
}
|
||||
|
||||
private static void clearThis( BoardDelegate self )
|
||||
{
|
||||
synchronized( s_this ) {
|
||||
Assert.assertTrue( s_this.contains( self ) );
|
||||
s_this.remove( self );
|
||||
}
|
||||
}
|
||||
|
||||
public class TimerRunnable implements Runnable {
|
||||
private int m_why;
|
||||
private int m_when;
|
||||
|
@ -231,7 +180,7 @@ public class BoardDelegate extends DelegateBase
|
|||
lstnr = new OnClickListener() {
|
||||
public void onClick( DialogInterface dlg,
|
||||
int whichButton ) {
|
||||
m_jniThread.handle( JNICmd.CMD_RESET );
|
||||
handleViaThread( JNICmd.CMD_RESET );
|
||||
}
|
||||
};
|
||||
ab.setNegativeButton( R.string.button_retry, lstnr );
|
||||
|
@ -421,8 +370,7 @@ public class BoardDelegate extends DelegateBase
|
|||
public void
|
||||
onClick( DialogInterface dlg,
|
||||
int item ) {
|
||||
m_jniThread.
|
||||
handle(JNICmd.CMD_ENDGAME);
|
||||
handleViaThread(JNICmd.CMD_ENDGAME);
|
||||
}
|
||||
})
|
||||
.setNegativeButton( R.string.button_no, null )
|
||||
|
@ -595,6 +543,7 @@ public class BoardDelegate extends DelegateBase
|
|||
m_timers = new TimerRunnable[4]; // needs to be in sync with
|
||||
// XWTimerReason
|
||||
m_view = (BoardView)findViewById( R.id.board_view );
|
||||
m_view.setBoardDelegate( this );
|
||||
if ( ! ABUtils.haveActionBar() ) {
|
||||
m_tradeButtons = findViewById( R.id.exchange_buttons );
|
||||
if ( null != m_tradeButtons ) {
|
||||
|
@ -614,20 +563,65 @@ public class BoardDelegate extends DelegateBase
|
|||
m_haveInvited = args.getBoolean( GameUtils.INVITED, false );
|
||||
m_overNotShown = true;
|
||||
|
||||
Handler handler = new Handler() {
|
||||
public void handleMessage( Message msg ) {
|
||||
switch( msg.what ) {
|
||||
case JNIThread.DIALOG:
|
||||
m_dlgBytes = (String)msg.obj;
|
||||
m_dlgTitle = msg.arg1;
|
||||
showDialog( DlgID.DLG_OKONLY );
|
||||
break;
|
||||
case JNIThread.QUERY_ENDGAME:
|
||||
showDialog( DlgID.QUERY_ENDGAME );
|
||||
break;
|
||||
case JNIThread.TOOLBAR_STATES:
|
||||
if ( null != m_jniThread ) {
|
||||
m_gsi =
|
||||
m_jniThread.getGameStateInfo();
|
||||
updateToolbar();
|
||||
if ( m_inTrade != m_gsi.inTrade ) {
|
||||
m_inTrade = m_gsi.inTrade;
|
||||
}
|
||||
m_view.setInTrade( m_inTrade );
|
||||
adjustTradeVisibility();
|
||||
invalidateOptionsMenuIf();
|
||||
}
|
||||
break;
|
||||
case JNIThread.GOT_WORDS:
|
||||
CurGameInfo gi = m_jniThreadRef.getGI();
|
||||
launchLookup( wordsToArray((String)msg.obj),
|
||||
gi.dictLang );
|
||||
break;
|
||||
case JNIThread.GAME_OVER:
|
||||
m_dlgBytes = (String)msg.obj;
|
||||
m_dlgTitle = msg.arg1;
|
||||
showDialog( DlgID.GAME_OVER );
|
||||
break;
|
||||
case JNIThread.MSGS_SENT:
|
||||
int nSent = (Integer)msg.obj;
|
||||
showToast( getQuantityString( R.plurals.resent_msgs_fmt,
|
||||
nSent, nSent ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
m_jniThreadRef = JNIThread.getRetained( m_rowid, true ).
|
||||
configure( m_activity, m_view, m_utils, this, handler );
|
||||
m_jniGamePtr = m_jniThreadRef.getGamePtr();
|
||||
Assert.assertNotNull( m_jniGamePtr );
|
||||
|
||||
// see http://stackoverflow.com/questions/680180/where-to-stop- \
|
||||
// destroy-threads-in-android-service-class
|
||||
m_jniThreadRef.setDaemonOnce( true ); // firing
|
||||
m_jniThreadRef.startOnce();
|
||||
|
||||
NFCUtils.register( m_activity, this ); // Don't seem to need to unregister...
|
||||
|
||||
setBackgroundColor();
|
||||
setKeepScreenOn();
|
||||
} // init
|
||||
|
||||
protected void onPause()
|
||||
{
|
||||
m_handler = null;
|
||||
ConnStatusHandler.setHandler( null );
|
||||
waitCloseGame( true );
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart()
|
||||
{
|
||||
|
@ -639,12 +633,41 @@ public class BoardDelegate extends DelegateBase
|
|||
protected void onResume()
|
||||
{
|
||||
super.onResume();
|
||||
// if( BuildConfig.DEBUG ) {
|
||||
// GameUtils.postSelfNotification( m_activity, m_rowid );
|
||||
// }
|
||||
doResume( false );
|
||||
}
|
||||
|
||||
protected void onPause()
|
||||
{
|
||||
closeIfFinishing( false );
|
||||
m_handler = null;
|
||||
ConnStatusHandler.setHandler( null );
|
||||
waitCloseGame( true );
|
||||
pauseGame();
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop()
|
||||
{
|
||||
if ( isFinishing() ) {
|
||||
m_jniThreadRef.release();
|
||||
m_jniThreadRef = null;
|
||||
}
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy()
|
||||
{
|
||||
closeIfFinishing( true );
|
||||
if ( null != m_jniThreadRef ) {
|
||||
m_jniThreadRef.release();
|
||||
m_jniThreadRef = null;
|
||||
// Assert.assertNull( m_jniThreadRef ); // firing
|
||||
}
|
||||
GamesListDelegate.boardDestroyed( m_rowid );
|
||||
super.onDestroy();
|
||||
}
|
||||
|
@ -718,7 +741,7 @@ public class BoardDelegate extends DelegateBase
|
|||
m_firingPrefs = false;
|
||||
m_volKeysZoom = XWPrefs.getVolKeysZoom( m_activity );
|
||||
if ( null != m_jniThread ) {
|
||||
m_jniThread.handle( JNICmd.CMD_PREFS_CHANGE );
|
||||
handleViaThread( JNICmd.CMD_PREFS_CHANGE );
|
||||
}
|
||||
// in case of change...
|
||||
setBackgroundColor();
|
||||
|
@ -731,13 +754,33 @@ public class BoardDelegate extends DelegateBase
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void orientationChanged()
|
||||
{
|
||||
boolean isPortrait = isPortrait();
|
||||
DbgUtils.logdf( "BoardDelegate.orientationChanged(isPortrait=%b)",
|
||||
isPortrait );
|
||||
positionToolbar( isPortrait );
|
||||
m_view.orientationChanged();
|
||||
}
|
||||
|
||||
private void positionToolbar( boolean isPortrait )
|
||||
{
|
||||
if ( null != findViewById( R.id.tbar_parent_hor ) ) {
|
||||
if ( null == m_toolbar ) {
|
||||
m_toolbar = new Toolbar( m_activity, this );
|
||||
}
|
||||
m_toolbar.setIsPortrait( isPortrait );
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean onKeyDown( int keyCode, KeyEvent event )
|
||||
{
|
||||
boolean handled = false;
|
||||
if ( null != m_jniThread ) {
|
||||
XwJNI.XP_Key xpKey = keyCodeToXPKey( keyCode );
|
||||
if ( XwJNI.XP_Key.XP_KEY_NONE != xpKey ) {
|
||||
m_jniThread.handle( JNICmd.CMD_KEYDOWN, xpKey );
|
||||
handleViaThread( JNICmd.CMD_KEYDOWN, xpKey );
|
||||
} else {
|
||||
switch( keyCode ) {
|
||||
case KeyEvent.KEYCODE_VOLUME_DOWN:
|
||||
|
@ -760,7 +803,7 @@ public class BoardDelegate extends DelegateBase
|
|||
if ( null != m_jniThread ) {
|
||||
XwJNI.XP_Key xpKey = keyCodeToXPKey( keyCode );
|
||||
if ( XwJNI.XP_Key.XP_KEY_NONE != xpKey ) {
|
||||
m_jniThread.handle( JNICmd.CMD_KEYUP, xpKey );
|
||||
handleViaThread( JNICmd.CMD_KEYUP, xpKey );
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
|
@ -923,10 +966,10 @@ public class BoardDelegate extends DelegateBase
|
|||
cmd = JNICmd.CMD_TOGGLE_TRAY;
|
||||
break;
|
||||
case R.id.games_menu_study:
|
||||
StudyListDelegate.launchOrAlert( m_activity, m_gi.dictLang, this );
|
||||
StudyListDelegate.launchOrAlert( getDelegator(), m_gi.dictLang, this );
|
||||
break;
|
||||
case R.id.board_menu_game_netstats:
|
||||
m_jniThread.handle( JNICmd.CMD_NETSTATS, R.string.netstats_title );
|
||||
handleViaThread( JNICmd.CMD_NETSTATS, R.string.netstats_title );
|
||||
break;
|
||||
case R.id.board_menu_game_invites:
|
||||
SentInvitesInfo sentInfo = DBUtils.getInvitesFor( m_activity, m_rowid );
|
||||
|
@ -942,28 +985,27 @@ public class BoardDelegate extends DelegateBase
|
|||
// small devices only
|
||||
case R.id.board_menu_dict:
|
||||
String dictName = m_gi.dictName( m_view.getCurPlayer() );
|
||||
DictBrowseDelegate.launch( m_activity, dictName );
|
||||
DictBrowseDelegate.launch( getDelegator(), dictName );
|
||||
break;
|
||||
|
||||
case R.id.board_menu_game_counts:
|
||||
m_jniThread.handle( JNICmd.CMD_COUNTS_VALUES,
|
||||
R.string.counts_values_title );
|
||||
handleViaThread( JNICmd.CMD_COUNTS_VALUES,
|
||||
R.string.counts_values_title );
|
||||
break;
|
||||
case R.id.board_menu_game_left:
|
||||
m_jniThread.handle( JNICmd.CMD_REMAINING,
|
||||
R.string.tiles_left_title );
|
||||
handleViaThread( JNICmd.CMD_REMAINING, R.string.tiles_left_title );
|
||||
break;
|
||||
|
||||
case R.id.board_menu_game_history:
|
||||
m_jniThread.handle( JNICmd.CMD_HISTORY, R.string.history_title );
|
||||
handleViaThread( JNICmd.CMD_HISTORY, R.string.history_title );
|
||||
break;
|
||||
|
||||
case R.id.board_menu_game_resign:
|
||||
m_jniThread.handle( JNICmd.CMD_FINAL, R.string.history_title );
|
||||
handleViaThread( JNICmd.CMD_FINAL, R.string.history_title );
|
||||
break;
|
||||
|
||||
case R.id.board_menu_game_resend:
|
||||
m_jniThread.handle( JNICmd.CMD_RESEND, true, false, true );
|
||||
handleViaThread( JNICmd.CMD_RESEND, true, false, true );
|
||||
break;
|
||||
|
||||
case R.id.gamel_menu_checkmoves:
|
||||
|
@ -983,7 +1025,7 @@ public class BoardDelegate extends DelegateBase
|
|||
}
|
||||
|
||||
if ( handled && cmd != JNICmd.CMD_NONE ) {
|
||||
m_jniThread.handle( cmd );
|
||||
handleViaThread( cmd );
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
@ -1021,11 +1063,11 @@ public class BoardDelegate extends DelegateBase
|
|||
String curDict = m_gi.dictName( m_view.getCurPlayer() );
|
||||
View button = m_toolbar.getViewFor( Toolbar.BUTTON_BROWSE_DICT );
|
||||
if ( Action.BUTTON_BROWSEALL_ACTION == action &&
|
||||
DictsActivity.handleDictsPopup( m_activity, button,
|
||||
DictsDelegate.handleDictsPopup( getDelegator(), button,
|
||||
curDict, m_gi.dictLang ) ){
|
||||
break;
|
||||
}
|
||||
DictBrowseDelegate.launch( m_activity, curDict );
|
||||
DictBrowseDelegate.launch( getDelegator(), curDict );
|
||||
break;
|
||||
case PREV_HINT_ACTION:
|
||||
cmd = JNICmd.CMD_PREV_HINT;
|
||||
|
@ -1083,7 +1125,7 @@ public class BoardDelegate extends DelegateBase
|
|||
}
|
||||
|
||||
if ( JNICmd.CMD_NONE != cmd ) {
|
||||
checkAndHandle( cmd );
|
||||
handleViaThread( cmd );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1148,9 +1190,9 @@ public class BoardDelegate extends DelegateBase
|
|||
public void onClick( View view )
|
||||
{
|
||||
if ( view == m_exchCommmitButton ) {
|
||||
m_jniThread.handle( JNICmd.CMD_COMMIT );
|
||||
handleViaThread( JNICmd.CMD_COMMIT );
|
||||
} else if ( view == m_exchCancelButton ) {
|
||||
m_jniThread.handle( JNICmd.CMD_CANCELTRADE );
|
||||
handleViaThread( JNICmd.CMD_CANCELTRADE );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1236,7 +1278,7 @@ public class BoardDelegate extends DelegateBase
|
|||
public void tpmRelayConnd( final String room, final int devOrder,
|
||||
final boolean allHere, final int nMissing )
|
||||
{
|
||||
post( new Runnable() {
|
||||
runOnUiThread( new Runnable() {
|
||||
public void run() {
|
||||
handleConndMessage( room, devOrder, allHere, nMissing );
|
||||
}
|
||||
|
@ -1390,8 +1432,8 @@ public class BoardDelegate extends DelegateBase
|
|||
|
||||
private void deleteAndClose()
|
||||
{
|
||||
GameUtils.deleteGame( m_activity, m_gameLock, false );
|
||||
waitCloseGame( false );
|
||||
GameUtils.deleteGame( m_activity, m_rowid, false );
|
||||
finish();
|
||||
}
|
||||
|
||||
|
@ -1422,7 +1464,7 @@ public class BoardDelegate extends DelegateBase
|
|||
|
||||
finish();
|
||||
|
||||
GameUtils.launchGame( m_activity, m_rowid, m_haveInvited );
|
||||
GameUtils.launchGame( getDelegator(), m_rowid, m_haveInvited );
|
||||
}
|
||||
|
||||
private void setGotGameDict( String getDict )
|
||||
|
@ -1432,7 +1474,7 @@ public class BoardDelegate extends DelegateBase
|
|||
String msg = getString( R.string.reload_new_dict_fmt, getDict );
|
||||
showToast( msg );
|
||||
finish();
|
||||
GameUtils.launchGame( m_activity, m_rowid, false );
|
||||
GameUtils.launchGame( getDelegator(), m_rowid, false );
|
||||
}
|
||||
|
||||
private XwJNI.XP_Key keyCodeToXPKey( int keyCode )
|
||||
|
@ -1579,7 +1621,7 @@ public class BoardDelegate extends DelegateBase
|
|||
@Override
|
||||
public void requestTime()
|
||||
{
|
||||
post( new Runnable() {
|
||||
runOnUiThread( new Runnable() {
|
||||
public void run() {
|
||||
if ( null != m_jniThread ) {
|
||||
m_jniThread.handleBkgrnd( JNICmd.CMD_DO );
|
||||
|
@ -1591,8 +1633,7 @@ public class BoardDelegate extends DelegateBase
|
|||
@Override
|
||||
public void remSelected()
|
||||
{
|
||||
m_jniThread.handle( JNICmd.CMD_REMAINING,
|
||||
R.string.tiles_left_title );
|
||||
handleViaThread( JNICmd.CMD_REMAINING, R.string.tiles_left_title );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1603,7 +1644,7 @@ public class BoardDelegate extends DelegateBase
|
|||
if ( newRole != m_gi.serverRole ) {
|
||||
m_gi.serverRole = newRole;
|
||||
if ( !isServer ) {
|
||||
m_jniThread.handle( JNICmd.CMD_SWITCHCLIENT );
|
||||
handleViaThread( JNICmd.CMD_SWITCHCLIENT );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1744,7 +1785,7 @@ public class BoardDelegate extends DelegateBase
|
|||
R.string.key_notagain_turnchanged );
|
||||
}
|
||||
} );
|
||||
m_jniThread.handle( JNICmd. CMD_ZOOM, -8 );
|
||||
handleViaThread( JNICmd. CMD_ZOOM, -8 );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1894,10 +1935,21 @@ public class BoardDelegate extends DelegateBase
|
|||
}
|
||||
|
||||
@Override
|
||||
public void informMove( String expl, String words )
|
||||
public void informMove( int turn, String expl, String words )
|
||||
{
|
||||
m_words = null == words? null : wordsToArray( words );
|
||||
nonBlockingDialog( DlgID.DLG_SCORES, expl );
|
||||
if ( isVisible() ) {
|
||||
Utils.playNotificationSound( m_activity );
|
||||
} else {
|
||||
LastMoveInfo lmi = new LastMoveInfo();
|
||||
XwJNI.model_getPlayersLastScore( m_jniGamePtr, turn, lmi );
|
||||
GameUtils.BackMoveResult bmr = new GameUtils.BackMoveResult();
|
||||
bmr.m_lmi = lmi;
|
||||
boolean[] locals = m_gi.playersLocal();
|
||||
GameUtils.postMoveNotification( m_activity, m_rowid,
|
||||
bmr, locals[turn] );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1947,7 +1999,7 @@ public class BoardDelegate extends DelegateBase
|
|||
public void notifyGameOver()
|
||||
{
|
||||
m_gameOver = true;
|
||||
m_jniThread.handle( JNICmd.CMD_POST_OVER );
|
||||
handleViaThread( JNICmd.CMD_POST_OVER );
|
||||
}
|
||||
|
||||
// public void yOffsetChange( int maxOffset, int oldOffset, int newOffset )
|
||||
|
@ -1983,14 +2035,18 @@ public class BoardDelegate extends DelegateBase
|
|||
// and may stack dialogs on top of this one. Including later
|
||||
// chat-messages.
|
||||
@Override
|
||||
public void showChat( final String msg, String fromPlayer )
|
||||
public void showChat( final String msg, final int fromIndx,
|
||||
String fromPlayer )
|
||||
{
|
||||
if ( BuildConstants.CHAT_SUPPORTED ) {
|
||||
post( new Runnable() {
|
||||
runOnUiThread( new Runnable() {
|
||||
public void run() {
|
||||
DBUtils.appendChatHistory( m_activity,
|
||||
m_rowid, msg, false );
|
||||
startChatActivity();
|
||||
DBUtils.appendChatHistory( m_activity, m_rowid, msg,
|
||||
fromIndx );
|
||||
if ( ! ChatDelegate.append( m_rowid, msg,
|
||||
fromIndx ) ) {
|
||||
startChatActivity();
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
@ -2006,7 +2062,7 @@ public class BoardDelegate extends DelegateBase
|
|||
}
|
||||
|
||||
try {
|
||||
loadGame( isStart );
|
||||
resumeGame( isStart );
|
||||
if ( !isStart ) {
|
||||
setKeepScreenOn();
|
||||
ConnStatusHandler.setHandler( this );
|
||||
|
@ -2016,159 +2072,176 @@ public class BoardDelegate extends DelegateBase
|
|||
}
|
||||
}
|
||||
|
||||
private void loadGame( boolean isStart )
|
||||
private void resumeGame( boolean isStart )
|
||||
{
|
||||
if ( null == m_jniGamePtr ) {
|
||||
try {
|
||||
String gameName = DBUtils.getName( m_activity, m_rowid );
|
||||
String[] dictNames = GameUtils.dictNames( m_activity, m_rowid );
|
||||
DictUtils.DictPairs pairs = DictUtils.openDicts( m_activity, dictNames );
|
||||
if ( null == m_jniThread ) {
|
||||
m_jniThread = m_jniThreadRef.retain();
|
||||
m_gi = m_jniThread.getGI();
|
||||
m_summary = m_jniThread.getSummary();
|
||||
m_gameLock = m_jniThread.getLock();
|
||||
|
||||
if ( pairs.anyMissing( dictNames ) ) {
|
||||
showDictGoneFinish();
|
||||
} else {
|
||||
Assert.assertNull( m_gameLock );
|
||||
m_gameLock = new GameLock( m_rowid, true ).lock();
|
||||
m_view.startHandling( m_activity, m_jniThread, m_connTypes );
|
||||
|
||||
byte[] stream = GameUtils.savedGame( m_activity, m_gameLock );
|
||||
m_gi = new CurGameInfo( m_activity );
|
||||
m_gi.setName( gameName );
|
||||
XwJNI.gi_from_stream( m_gi, stream );
|
||||
String langName = m_gi.langName();
|
||||
handleViaThread( JNICmd.CMD_START );
|
||||
|
||||
m_summary = DBUtils.getSummary( m_activity, m_gameLock );
|
||||
m_relayMissing = m_summary.relayConnectPending();
|
||||
if ( !CommonPrefs.getHideTitleBar( m_activity ) ) {
|
||||
setTitle( GameUtils.getName( m_activity, m_rowid ) );
|
||||
}
|
||||
|
||||
setThis( this );
|
||||
positionToolbar( isPortrait() );
|
||||
populateToolbar();
|
||||
adjustTradeVisibility();
|
||||
|
||||
m_jniGamePtr = XwJNI.initJNI( m_rowid );
|
||||
|
||||
if ( m_gi.serverRole != DeviceRole.SERVER_STANDALONE ) {
|
||||
m_xport = new CommsTransport( m_activity, this, m_rowid,
|
||||
m_gi.serverRole );
|
||||
}
|
||||
|
||||
CommonPrefs cp = CommonPrefs.get( m_activity );
|
||||
if ( null == stream ||
|
||||
! XwJNI.game_makeFromStream( m_jniGamePtr, stream,
|
||||
m_gi, dictNames,
|
||||
pairs.m_bytes,
|
||||
pairs.m_paths, langName,
|
||||
m_utils, m_jniu,
|
||||
null, cp, m_xport ) ) {
|
||||
XwJNI.game_makeNewGame( m_jniGamePtr, m_gi, m_utils,
|
||||
m_jniu, null, cp, m_xport,
|
||||
dictNames, pairs.m_bytes,
|
||||
pairs.m_paths, langName );
|
||||
}
|
||||
|
||||
Handler handler = new Handler() {
|
||||
public void handleMessage( Message msg ) {
|
||||
switch( msg.what ) {
|
||||
case JNIThread.DIALOG:
|
||||
m_dlgBytes = (String)msg.obj;
|
||||
m_dlgTitle = msg.arg1;
|
||||
showDialog( DlgID.DLG_OKONLY );
|
||||
break;
|
||||
case JNIThread.QUERY_ENDGAME:
|
||||
showDialog( DlgID.QUERY_ENDGAME );
|
||||
break;
|
||||
case JNIThread.TOOLBAR_STATES:
|
||||
if ( null != m_jniThread ) {
|
||||
m_gsi =
|
||||
m_jniThread.getGameStateInfo();
|
||||
updateToolbar();
|
||||
if ( m_inTrade != m_gsi.inTrade ) {
|
||||
m_inTrade = m_gsi.inTrade;
|
||||
}
|
||||
m_view.setInTrade( m_inTrade );
|
||||
adjustTradeVisibility();
|
||||
invalidateOptionsMenuIf();
|
||||
}
|
||||
break;
|
||||
case JNIThread.GOT_WORDS:
|
||||
launchLookup( wordsToArray((String)msg.obj),
|
||||
m_gi.dictLang );
|
||||
break;
|
||||
case JNIThread.GAME_OVER:
|
||||
m_dlgBytes = (String)msg.obj;
|
||||
m_dlgTitle = msg.arg1;
|
||||
showDialog( DlgID.GAME_OVER );
|
||||
break;
|
||||
case JNIThread.MSGS_SENT:
|
||||
int nSent = (Integer)msg.obj;
|
||||
showToast( getQuantityString( R.plurals.resent_msgs_fmt,
|
||||
nSent, nSent ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
m_jniThread =
|
||||
new JNIThread( m_jniGamePtr, stream, m_gi,
|
||||
m_view, m_gameLock, m_activity, handler );
|
||||
// see http://stackoverflow.com/questions/680180/where-to-stop-\
|
||||
// destroy-threads-in-android-service-class
|
||||
m_jniThread.setDaemon( true );
|
||||
m_jniThread.start();
|
||||
|
||||
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 );
|
||||
|
||||
if ( !CommonPrefs.getHideTitleBar( m_activity ) ) {
|
||||
setTitle( GameUtils.getName( m_activity, m_rowid ) );
|
||||
}
|
||||
|
||||
if ( null != findViewById( R.id.tbar_parent_hor ) ) {
|
||||
int orient = m_activity.getResources().getConfiguration().orientation;
|
||||
boolean isLandscape = Configuration.ORIENTATION_LANDSCAPE == orient;
|
||||
m_toolbar = new Toolbar( m_activity, this, isLandscape );
|
||||
}
|
||||
|
||||
populateToolbar();
|
||||
adjustTradeVisibility();
|
||||
|
||||
int flags = DBUtils.getMsgFlags( m_activity, m_rowid );
|
||||
if ( 0 != (GameSummary.MSG_FLAGS_CHAT & flags) ) {
|
||||
startChatActivity();
|
||||
}
|
||||
if ( m_overNotShown ) {
|
||||
boolean auto = false;
|
||||
if ( 0 != (GameSummary.MSG_FLAGS_GAMEOVER & flags) ) {
|
||||
m_gameOver = true;
|
||||
} else if ( DBUtils.gameOver( m_activity, m_rowid ) ) {
|
||||
m_gameOver = true;
|
||||
auto = true;
|
||||
}
|
||||
if ( m_gameOver ) {
|
||||
m_overNotShown = false;
|
||||
m_jniThread.handle( JNICmd.CMD_POST_OVER, auto );
|
||||
}
|
||||
}
|
||||
if ( 0 != flags ) {
|
||||
DBUtils.setMsgFlags( m_rowid, GameSummary.MSG_FLAGS_NONE );
|
||||
}
|
||||
|
||||
Utils.cancelNotification( m_activity, (int)m_rowid );
|
||||
|
||||
if ( null != m_xport ) {
|
||||
warnIfNoTransport();
|
||||
trySendChats();
|
||||
tickle( isStart );
|
||||
tryInvites();
|
||||
}
|
||||
int flags = DBUtils.getMsgFlags( m_activity, m_rowid );
|
||||
if ( 0 != (GameSummary.MSG_FLAGS_CHAT & flags) ) {
|
||||
startChatActivity();
|
||||
}
|
||||
if ( m_overNotShown ) {
|
||||
boolean auto = false;
|
||||
if ( 0 != (GameSummary.MSG_FLAGS_GAMEOVER & flags) ) {
|
||||
m_gameOver = true;
|
||||
} else if ( DBUtils.gameOver( m_activity, m_rowid ) ) {
|
||||
m_gameOver = true;
|
||||
auto = true;
|
||||
}
|
||||
} catch ( GameUtils.NoSuchGameException nsge ) {
|
||||
DbgUtils.loge( nsge );
|
||||
finish();
|
||||
if ( m_gameOver ) {
|
||||
m_overNotShown = false;
|
||||
handleViaThread( JNICmd.CMD_POST_OVER, auto );
|
||||
}
|
||||
}
|
||||
if ( 0 != flags ) {
|
||||
DBUtils.setMsgFlags( m_rowid, GameSummary.MSG_FLAGS_NONE );
|
||||
}
|
||||
|
||||
Utils.cancelNotification( m_activity, (int)m_rowid );
|
||||
|
||||
if ( m_gi.serverRole != DeviceRole.SERVER_STANDALONE ) {
|
||||
warnIfNoTransport();
|
||||
trySendChats();
|
||||
tickle( isStart );
|
||||
tryInvites();
|
||||
}
|
||||
}
|
||||
} // loadGame
|
||||
} // resumeGame
|
||||
|
||||
// private void loadGame( boolean isStart )
|
||||
// {
|
||||
// if ( null == m_jniGamePtr ) {
|
||||
// try {
|
||||
// String gameName = DBUtils.getName( m_activity, m_rowid );
|
||||
// String[] dictNames;
|
||||
|
||||
// Assert.assertNull( m_gameLock );
|
||||
// m_gameLock = m_jniThreadRef.getLock();
|
||||
// if ( null == m_gameLock ) {
|
||||
// dictNames = GameUtils.dictNames( m_activity, m_rowid );
|
||||
// } else {
|
||||
// dictNames = GameUtils.dictNames( m_activity, m_gameLock );
|
||||
// }
|
||||
// DictUtils.DictPairs pairs = DictUtils.openDicts( m_activity, dictNames );
|
||||
|
||||
// if ( pairs.anyMissing( dictNames ) ) {
|
||||
// showDictGoneFinish();
|
||||
// } else {
|
||||
// if ( null == m_gameLock ) {
|
||||
// m_gameLock = new GameLock( m_rowid, true ).lock();
|
||||
// }
|
||||
|
||||
// // PENDING: there's no point in re-opening the game if
|
||||
// // it's already open!
|
||||
// byte[] stream = GameUtils.savedGame( m_activity, m_gameLock );
|
||||
// m_gi = new CurGameInfo( m_activity );
|
||||
// m_gi.setName( gameName );
|
||||
// XwJNI.gi_from_stream( m_gi, stream );
|
||||
// String langName = m_gi.langName();
|
||||
|
||||
// m_summary = DBUtils.getSummary( m_activity, m_gameLock );
|
||||
// m_relayMissing = m_summary.relayConnectPending();
|
||||
|
||||
// setThis( this );
|
||||
|
||||
// m_jniGamePtr = XwJNI.initJNI( m_rowid );
|
||||
|
||||
// if ( m_gi.serverRole != DeviceRole.SERVER_STANDALONE ) {
|
||||
// m_xport = new CommsTransport( m_activity, this, m_rowid,
|
||||
// m_gi.serverRole );
|
||||
// }
|
||||
|
||||
// CommonPrefs cp = CommonPrefs.get( m_activity );
|
||||
// if ( null == stream ||
|
||||
// ! XwJNI.game_makeFromStream( m_jniGamePtr, stream,
|
||||
// m_gi, dictNames,
|
||||
// pairs.m_bytes,
|
||||
// pairs.m_paths, langName,
|
||||
// m_utils, m_jniu,
|
||||
// null, cp, m_xport ) ) {
|
||||
// XwJNI.game_makeNewGame( m_jniGamePtr, m_gi, m_utils,
|
||||
// m_jniu, null, cp, m_xport,
|
||||
// dictNames, pairs.m_bytes,
|
||||
// pairs.m_paths, langName );
|
||||
// }
|
||||
|
||||
|
||||
// m_jniThread = m_jniThreadRef.retain();
|
||||
|
||||
// // see http://stackoverflow.com/questions/680180/where-to-stop-\
|
||||
// // destroy-threads-in-android-service-class
|
||||
// // m_jniThread.setDaemonOnce( true ); // firing
|
||||
// // m_jniThread.startOnce();
|
||||
|
||||
// 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 );
|
||||
// }
|
||||
// handleViaThread( JNICmd.CMD_START );
|
||||
|
||||
// if ( !CommonPrefs.getHideTitleBar( m_activity ) ) {
|
||||
// setTitle( GameUtils.getName( m_activity, m_rowid ) );
|
||||
// }
|
||||
|
||||
// positionToolbar( isPortrait() );
|
||||
// populateToolbar();
|
||||
// adjustTradeVisibility();
|
||||
|
||||
// int flags = DBUtils.getMsgFlags( m_activity, m_rowid );
|
||||
// if ( 0 != (GameSummary.MSG_FLAGS_CHAT & flags) ) {
|
||||
// startChatActivity();
|
||||
// }
|
||||
// if ( m_overNotShown ) {
|
||||
// boolean auto = false;
|
||||
// if ( 0 != (GameSummary.MSG_FLAGS_GAMEOVER & flags) ) {
|
||||
// m_gameOver = true;
|
||||
// } else if ( DBUtils.gameOver( m_activity, m_rowid ) ) {
|
||||
// m_gameOver = true;
|
||||
// auto = true;
|
||||
// }
|
||||
// if ( m_gameOver ) {
|
||||
// m_overNotShown = false;
|
||||
// handleViaThread( JNICmd.CMD_POST_OVER, auto );
|
||||
// }
|
||||
// }
|
||||
// if ( 0 != flags ) {
|
||||
// DBUtils.setMsgFlags( m_rowid, GameSummary.MSG_FLAGS_NONE );
|
||||
// }
|
||||
|
||||
// Utils.cancelNotification( m_activity, (int)m_rowid );
|
||||
|
||||
// if ( null != m_xport ) {
|
||||
// warnIfNoTransport();
|
||||
// trySendChats();
|
||||
// tickle( isStart );
|
||||
// tryInvites();
|
||||
// }
|
||||
// }
|
||||
// } catch ( GameUtils.NoSuchGameException nsge ) {
|
||||
// DbgUtils.loge( nsge );
|
||||
// finish();
|
||||
// }
|
||||
// }
|
||||
// } // loadGame
|
||||
|
||||
private void tickle( boolean force )
|
||||
{
|
||||
|
@ -2190,8 +2263,7 @@ public class BoardDelegate extends DelegateBase
|
|||
}
|
||||
|
||||
if ( 0 < m_connTypes.size() ) {
|
||||
m_jniThread.handle( JNIThread.JNICmd.CMD_RESEND, force, true,
|
||||
false );
|
||||
handleViaThread( JNIThread.JNICmd.CMD_RESEND, force, true, false );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2223,13 +2295,6 @@ public class BoardDelegate extends DelegateBase
|
|||
}
|
||||
}
|
||||
|
||||
private void checkAndHandle( JNICmd cmd )
|
||||
{
|
||||
if ( null != m_jniThread ) {
|
||||
m_jniThread.handle( cmd );
|
||||
}
|
||||
}
|
||||
|
||||
private void populateToolbar()
|
||||
{
|
||||
if ( null != m_toolbar ) {
|
||||
|
@ -2344,7 +2409,7 @@ public class BoardDelegate extends DelegateBase
|
|||
}
|
||||
|
||||
m_dlgBytes = txt;
|
||||
post( new Runnable() {
|
||||
runOnUiThread( new Runnable() {
|
||||
public void run() {
|
||||
showDialog( dlgID );
|
||||
}
|
||||
|
@ -2355,7 +2420,7 @@ public class BoardDelegate extends DelegateBase
|
|||
{
|
||||
boolean handled = null != m_jniThread;
|
||||
if ( handled ) {
|
||||
m_jniThread.handle( JNICmd.CMD_ZOOM, zoomBy );
|
||||
handleViaThread( JNICmd.CMD_ZOOM, zoomBy );
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
@ -2363,29 +2428,38 @@ public class BoardDelegate extends DelegateBase
|
|||
private void startChatActivity()
|
||||
{
|
||||
if ( BuildConstants.CHAT_SUPPORTED ) {
|
||||
Intent intent = new Intent( m_activity, ChatActivity.class );
|
||||
intent.putExtra( GameUtils.INTENT_KEY_ROWID, m_rowid );
|
||||
startActivityForResult( intent, RequestCode.CHAT_REQUEST );
|
||||
int curPlayer = XwJNI.board_getSelPlayer( m_jniGamePtr );
|
||||
String[] names = m_gi.playerNames();
|
||||
boolean[] locs = m_gi.playersLocal(); // to convert old histories
|
||||
ChatDelegate.startForResult( getDelegator(), RequestCode.CHAT_REQUEST,
|
||||
m_rowid, curPlayer, names, locs );
|
||||
}
|
||||
}
|
||||
|
||||
private void waitCloseGame( boolean save )
|
||||
private void closeIfFinishing( boolean force )
|
||||
{
|
||||
if ( null != m_jniGamePtr ) {
|
||||
if ( null != m_xport ) {
|
||||
m_xport.waitToStop();
|
||||
m_xport = null;
|
||||
}
|
||||
if ( null == m_handler ) {
|
||||
// DbgUtils.logf( "closeIfFinishing(): already closed" );
|
||||
} else if ( force || isFinishing() ) {
|
||||
// DbgUtils.logf( "closeIfFinishing: closing rowid %d", m_rowid );
|
||||
m_handler = null;
|
||||
ConnStatusHandler.setHandler( null );
|
||||
waitCloseGame( true );
|
||||
} else {
|
||||
handleViaThread( JNICmd.CMD_SAVE );
|
||||
// DbgUtils.logf( "closeIfFinishing(): not finishing (yet)" );
|
||||
}
|
||||
}
|
||||
|
||||
private void pauseGame()
|
||||
{
|
||||
if ( null != m_jniThread ) {
|
||||
interruptBlockingThread();
|
||||
|
||||
if ( null != m_jniThread ) {
|
||||
m_jniThread.waitToStop( save );
|
||||
m_jniThread = null;
|
||||
}
|
||||
m_view.stopHandling();
|
||||
m_jniThread.release();
|
||||
m_jniThread = null;
|
||||
|
||||
clearThis( this );
|
||||
m_view.stopHandling();
|
||||
|
||||
if ( XWPrefs.getThumbEnabled( m_activity ) ) {
|
||||
// Before we dispose, and after JNIThread has
|
||||
|
@ -2395,11 +2469,18 @@ public class BoardDelegate extends DelegateBase
|
|||
DBUtils.saveThumbnail( m_activity, m_gameLock, thumb );
|
||||
}
|
||||
|
||||
m_jniGamePtr.release();
|
||||
m_jniGamePtr = null;
|
||||
m_gi = null;
|
||||
m_gameLock = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void waitCloseGame( boolean save )
|
||||
{
|
||||
pauseGame();
|
||||
if ( null != m_jniThread ) {
|
||||
// m_jniGamePtr.release();
|
||||
// m_jniGamePtr = null;
|
||||
|
||||
m_gameLock.unlock();
|
||||
// m_gameLock.unlock(); // likely the problem
|
||||
m_gameLock = null;
|
||||
}
|
||||
}
|
||||
|
@ -2421,7 +2502,7 @@ public class BoardDelegate extends DelegateBase
|
|||
if ( BuildConstants.CHAT_SUPPORTED && null != m_jniThread ) {
|
||||
Iterator<String> iter = m_pendingChats.iterator();
|
||||
while ( iter.hasNext() ) {
|
||||
m_jniThread.handle( JNICmd.CMD_SENDCHAT, iter.next() );
|
||||
handleViaThread( JNICmd.CMD_SENDCHAT, iter.next() );
|
||||
}
|
||||
m_pendingChats.clear();
|
||||
}
|
||||
|
@ -2554,7 +2635,8 @@ public class BoardDelegate extends DelegateBase
|
|||
if ( canPost ) {
|
||||
m_handler.post( runnable );
|
||||
} else {
|
||||
DbgUtils.logf( "post: dropping because handler null" );
|
||||
DbgUtils.logf( "BoardDelegate.post(): dropping b/c handler null" );
|
||||
DbgUtils.printStack();
|
||||
}
|
||||
return canPost;
|
||||
}
|
||||
|
@ -2776,10 +2858,13 @@ public class BoardDelegate extends DelegateBase
|
|||
DBUtils.recordInviteSent( m_activity, m_rowid, means, dev );
|
||||
}
|
||||
|
||||
private static void noteSkip()
|
||||
private void handleViaThread( JNICmd cmd, Object... args )
|
||||
{
|
||||
String msg = "BoardActivity.feedMessage[s](): skipped because "
|
||||
+ "too many open Boards";
|
||||
DbgUtils.logf(msg );
|
||||
if ( null == m_jniThread ) {
|
||||
DbgUtils.logf( "BoardDelegate: not calling handle(%s)", cmd.toString() );
|
||||
DbgUtils.printStack();
|
||||
} else {
|
||||
m_jniThread.handle( cmd, args );
|
||||
}
|
||||
}
|
||||
} // class BoardDelegate
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/* -*- compile-command: "find-and-ant.sh debug install"; -*- */
|
||||
/*
|
||||
* Copyright 2014 - 2016 by Eric House (xwords@eehouse.org). All rights
|
||||
* reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package org.eehouse.android.xw4;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
public class BoardFrag extends XWFragment {
|
||||
|
||||
@Override
|
||||
public void onCreate( Bundle sis )
|
||||
{
|
||||
super.onCreate( new BoardDelegate( this, sis ), sis, true );
|
||||
}
|
||||
}
|
|
@ -55,6 +55,7 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
|
|||
private static final int PINCH_THRESHOLD = 40;
|
||||
|
||||
private Context m_context;
|
||||
private BoardDelegate m_boardDlgt;
|
||||
private int m_defaultFontHt;
|
||||
private int m_mediumFontHt;
|
||||
private Runnable m_invalidator;
|
||||
|
@ -62,6 +63,7 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
|
|||
private CurGameInfo m_gi;
|
||||
private boolean m_isSolo;
|
||||
private int m_layoutWidth;
|
||||
private int m_dimsTossCount; // hack hack hack!!
|
||||
private int m_layoutHeight;
|
||||
private BoardCanvas m_canvas; // owns the bitmap
|
||||
private JNIThread m_jniThread;
|
||||
|
@ -103,17 +105,17 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
|
|||
case MotionEvent.ACTION_DOWN:
|
||||
m_lastSpacing = MULTI_INACTIVE;
|
||||
if ( !ConnStatusHandler.handleDown( xx, yy ) ) {
|
||||
m_jniThread.handle( JNIThread.JNICmd.CMD_PEN_DOWN, xx, yy );
|
||||
handle( JNIThread.JNICmd.CMD_PEN_DOWN, xx, yy );
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if ( ConnStatusHandler.handleMove( xx, yy ) ) {
|
||||
} else if ( MULTI_INACTIVE == m_lastSpacing ) {
|
||||
m_jniThread.handle( JNIThread.JNICmd.CMD_PEN_MOVE, xx, yy );
|
||||
handle( JNIThread.JNICmd.CMD_PEN_MOVE, xx, yy );
|
||||
} else {
|
||||
int zoomBy = figureZoom( event );
|
||||
if ( 0 != zoomBy ) {
|
||||
m_jniThread.handle( JNIThread.JNICmd.CMD_ZOOM,
|
||||
handle( JNIThread.JNICmd.CMD_ZOOM,
|
||||
zoomBy < 0 ? -2 : 2 );
|
||||
}
|
||||
}
|
||||
|
@ -122,12 +124,12 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
|
|||
if ( ConnStatusHandler.handleUp( xx, yy ) ) {
|
||||
// do nothing
|
||||
} else {
|
||||
m_jniThread.handle( JNIThread.JNICmd.CMD_PEN_UP, xx, yy );
|
||||
handle( JNIThread.JNICmd.CMD_PEN_UP, xx, yy );
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
case MotionEvent.ACTION_POINTER_2_DOWN:
|
||||
m_jniThread.handle( JNIThread.JNICmd.CMD_PEN_UP, xx, yy );
|
||||
handle( JNIThread.JNICmd.CMD_PEN_UP, xx, yy );
|
||||
m_lastSpacing = getSpacing( event );
|
||||
break;
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
|
@ -142,33 +144,24 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
|
|||
return wantMore; // true required to get subsequent events
|
||||
}
|
||||
|
||||
// private void printMode( String comment, int mode )
|
||||
// {
|
||||
// comment += ": ";
|
||||
// switch( mode ) {
|
||||
// case View.MeasureSpec.AT_MOST:
|
||||
// comment += "AT_MOST";
|
||||
// break;
|
||||
// case View.MeasureSpec.EXACTLY:
|
||||
// comment += "EXACTLY";
|
||||
// break;
|
||||
// case View.MeasureSpec.UNSPECIFIED:
|
||||
// comment += "UNSPECIFIED";
|
||||
// break;
|
||||
// default:
|
||||
// comment += "<bogus>";
|
||||
// }
|
||||
// DbgUtils.logf( comment );
|
||||
// }
|
||||
|
||||
@Override
|
||||
protected void onMeasure( int widthMeasureSpec, int heightMeasureSpec )
|
||||
{
|
||||
// One of the android sample apps ignores mode entirely:
|
||||
// int w = MeasureSpec.getSize(widthMeasureSpec);
|
||||
// int h = MeasureSpec.getSize(heightMeasureSpec);
|
||||
// int d = w == 0 ? h : h == 0 ? w : w < h ? w : h;
|
||||
// setMeasuredDimension(d, d);
|
||||
// DbgUtils.logf( "onMeasure(width: %s, height: %s)",
|
||||
// MeasureSpec.toString( widthMeasureSpec ),
|
||||
// MeasureSpec.toString( heightMeasureSpec ) );
|
||||
|
||||
if ( null != m_dims ) {
|
||||
if ( m_boardDlgt.isPortrait() != (m_dims.height > m_dims.width) ) {
|
||||
// square possible; will break above!
|
||||
Assert.assertTrue( m_dims.height != m_dims.width );
|
||||
DbgUtils.logf( "onMeasure: discarding m_dims" );
|
||||
if ( ++m_dimsTossCount < 4 ) {
|
||||
m_dims = null;
|
||||
m_layoutWidth = m_layoutHeight = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int width, height;
|
||||
m_measuredFromDims = null != m_dims;
|
||||
|
@ -189,8 +182,17 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
|
|||
width = minWidth;
|
||||
}
|
||||
setMeasuredDimension( width, height );
|
||||
DbgUtils.logdf( "BoardView.onMeasure: calling setMeasuredDimension( width=%d, height=%d )",
|
||||
width, height );
|
||||
}
|
||||
|
||||
// public void onSizeChanged( int width, int height, int oldWidth, int oldHeight )
|
||||
// {
|
||||
// DbgUtils.logf( "BoardView.onSizeChanged(): width: %d => %d; height: %d => %d",
|
||||
// oldWidth, width, oldHeight, height );
|
||||
// super.onSizeChanged( width, height, oldWidth, oldHeight );
|
||||
// }
|
||||
|
||||
// This will be called from the UI thread
|
||||
@Override
|
||||
protected void onDraw( Canvas canvas )
|
||||
|
@ -201,7 +203,7 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
|
|||
ConnStatusHandler.draw( m_context, canvas, getResources(),
|
||||
m_connTypes, m_isSolo );
|
||||
} else {
|
||||
DbgUtils.logf( "board not laid out yet" );
|
||||
DbgUtils.logf( "BoardView.onDraw(): board not laid out yet" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -212,12 +214,15 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
|
|||
final int height = getHeight();
|
||||
boolean layoutDone = width == m_layoutWidth && height == m_layoutHeight;
|
||||
if ( layoutDone ) {
|
||||
// nothing to do
|
||||
DbgUtils.logf( "layoutBoardOnce(): layoutDone true" );
|
||||
} else if ( null == m_gi ) {
|
||||
// nothing to do either
|
||||
DbgUtils.logf( "layoutBoardOnce(): no m_gi" );
|
||||
} else if ( null == m_jniThread ) {
|
||||
// nothing to do either
|
||||
DbgUtils.logf( "layoutBoardOnce(): no m_jniThread" );
|
||||
} else if ( null == m_dims ) {
|
||||
DbgUtils.logf( "layoutBoardOnce(): null m_dims" );
|
||||
// m_canvas = null;
|
||||
// need to synchronize??
|
||||
Paint paint = new Paint();
|
||||
|
@ -228,10 +233,12 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
|
|||
int timerWidth = scratch.width();
|
||||
int fontWidth =
|
||||
Math.min(m_defaultFontHt, timerWidth / timerTxt.length());
|
||||
m_jniThread.handle( JNIThread.JNICmd.CMD_LAYOUT, width, height,
|
||||
DbgUtils.logf( "layoutBoardOnce(): posting JNICmd.CMD_LAYOUT(w=%d, h=%d)", width, height );
|
||||
handle( JNIThread.JNICmd.CMD_LAYOUT, width, height,
|
||||
fontWidth, m_defaultFontHt );
|
||||
// We'll be back....
|
||||
} else {
|
||||
DbgUtils.logf( "layoutBoardOnce(): DOING IT" );
|
||||
// If board size has changed we need a new bitmap
|
||||
int bmHeight = 1 + m_dims.height;
|
||||
int bmWidth = 1 + m_dims.width;
|
||||
|
@ -257,37 +264,43 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
|
|||
} else {
|
||||
m_canvas.setJNIThread( m_jniThread );
|
||||
}
|
||||
m_jniThread.handle( JNIThread.JNICmd.CMD_SETDRAW, m_canvas );
|
||||
m_jniThread.handle( JNIThread.JNICmd.CMD_DRAW );
|
||||
handle( JNIThread.JNICmd.CMD_SETDRAW, m_canvas );
|
||||
handle( JNIThread.JNICmd.CMD_DRAW );
|
||||
|
||||
// set so we know we're done
|
||||
m_layoutWidth = width;
|
||||
m_layoutHeight = height;
|
||||
layoutDone = true;
|
||||
}
|
||||
DbgUtils.logf( "layoutBoardOnce()=>%b", layoutDone );
|
||||
return layoutDone;
|
||||
} // layoutBoardOnce
|
||||
|
||||
protected void setBoardDelegate( BoardDelegate dlgt )
|
||||
{
|
||||
m_boardDlgt = dlgt;
|
||||
}
|
||||
|
||||
// BoardHandler interface implementation
|
||||
public void startHandling( Activity parent, JNIThread thread,
|
||||
XwJNI.GamePtr gamePtr, CurGameInfo gi,
|
||||
CommsConnTypeSet connTypes )
|
||||
{
|
||||
DbgUtils.logf( "BoardView.startHandling(thread=%H)", thread );
|
||||
m_parent = parent;
|
||||
m_jniThread = thread;
|
||||
m_jniGamePtr = gamePtr;
|
||||
m_gi = gi;
|
||||
m_isSolo = CurGameInfo.DeviceRole.SERVER_STANDALONE == gi.serverRole;
|
||||
m_jniGamePtr = thread.getGamePtr();
|
||||
m_gi = thread.getGI();
|
||||
m_isSolo = CurGameInfo.DeviceRole.SERVER_STANDALONE == m_gi.serverRole;
|
||||
m_connTypes = connTypes;
|
||||
m_layoutWidth = 0;
|
||||
m_layoutHeight = 0;
|
||||
|
||||
s_isFirstDraw = s_curGameID != gi.gameID;
|
||||
s_curGameID = gi.gameID;
|
||||
s_isFirstDraw = s_curGameID != m_gi.gameID;
|
||||
s_curGameID = m_gi.gameID;
|
||||
|
||||
// Set the jni layout if we already have one
|
||||
if ( null != m_dims ) {
|
||||
m_jniThread.handle( JNIThread.JNICmd.CMD_LAYOUT, m_dims );
|
||||
handle( JNIThread.JNICmd.CMD_LAYOUT, m_dims );
|
||||
}
|
||||
|
||||
// Make sure we draw. Sometimes when we're reloading after
|
||||
|
@ -307,19 +320,22 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
|
|||
// SyncedDraw interface implementation
|
||||
public void doJNIDraw()
|
||||
{
|
||||
boolean drew;
|
||||
boolean drew = false;
|
||||
synchronized( this ) {
|
||||
if ( !XwJNI.board_draw( m_jniGamePtr ) ) {
|
||||
DbgUtils.logf( "doJNIDraw: draw not complete" );
|
||||
if ( null != m_jniGamePtr ) {
|
||||
drew = XwJNI.board_draw( m_jniGamePtr );
|
||||
}
|
||||
}
|
||||
|
||||
// Force update now that we have bits to copy
|
||||
m_parent.runOnUiThread( m_invalidator );
|
||||
if ( drew ) {
|
||||
m_parent.runOnUiThread( m_invalidator );
|
||||
}
|
||||
}
|
||||
|
||||
public void dimsChanged( BoardDims dims )
|
||||
{
|
||||
DbgUtils.logdf( "dimsChanged(%s)", dims.toString() );
|
||||
m_dims = dims;
|
||||
m_parent.runOnUiThread( new Runnable() {
|
||||
public void run()
|
||||
|
@ -329,6 +345,14 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
|
|||
});
|
||||
}
|
||||
|
||||
protected void orientationChanged()
|
||||
{
|
||||
m_dims = null;
|
||||
m_layoutWidth = m_layoutHeight = 0;
|
||||
m_dimsTossCount = 0;
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
public void setInTrade( boolean inTrade )
|
||||
{
|
||||
if ( null != m_canvas ) {
|
||||
|
@ -373,4 +397,13 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
|
|||
return zoomDir;
|
||||
}
|
||||
|
||||
private void handle( JNIThread.JNICmd cmd, Object... args )
|
||||
{
|
||||
if ( null == m_jniThread ) {
|
||||
DbgUtils.logf( "BoardView: not calling handle(%s)", cmd.toString() );
|
||||
DbgUtils.printStack();
|
||||
} else {
|
||||
m_jniThread.handle( cmd, args );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,19 +28,34 @@ import android.text.Editable;
|
|||
import android.text.TextWatcher;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View.OnLayoutChangeListener;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.TableLayout;
|
||||
import android.widget.TableRow;
|
||||
import android.widget.TextView;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.eehouse.android.xw4.DlgDelegate.Action;
|
||||
import org.eehouse.android.xw4.jni.JNIThread;
|
||||
|
||||
public class ChatDelegate extends DelegateBase {
|
||||
|
||||
private static final String INTENT_KEY_PLAYER = "intent_key_player";
|
||||
private static final String INTENT_KEY_NAMES = "intent_key_names";
|
||||
private static final String INTENT_KEY_LOCS = "intent_key_locs";
|
||||
|
||||
private static ChatDelegate s_visibleThis;
|
||||
private long m_rowid;
|
||||
private int m_curPlayer;
|
||||
private String[] m_names;
|
||||
private Activity m_activity;
|
||||
private EditText mEdit;
|
||||
private EditText m_edit;
|
||||
private TableLayout m_layout;
|
||||
private ScrollView m_scroll;
|
||||
private JNIThread m_jniThreadRef;
|
||||
|
||||
public ChatDelegate( Delegator delegator, Bundle savedInstanceState )
|
||||
{
|
||||
|
@ -51,9 +66,10 @@ public class ChatDelegate extends DelegateBase {
|
|||
@Override
|
||||
protected void init( Bundle savedInstanceState )
|
||||
{
|
||||
DbgUtils.logf( "ChatDelegate.init()" );
|
||||
if ( BuildConstants.CHAT_SUPPORTED ) {
|
||||
mEdit = (EditText)findViewById( R.id.chat_edit );
|
||||
mEdit.addTextChangedListener( new TextWatcher() {
|
||||
m_edit = (EditText)findViewById( R.id.chat_edit );
|
||||
m_edit.addTextChangedListener( new TextWatcher() {
|
||||
public void afterTextChanged( Editable s ) {
|
||||
invalidateOptionsMenuIf();
|
||||
}
|
||||
|
@ -63,30 +79,31 @@ public class ChatDelegate extends DelegateBase {
|
|||
int before, int count ) {}
|
||||
} );
|
||||
|
||||
m_rowid = getIntent().getLongExtra( GameUtils.INTENT_KEY_ROWID, -1 );
|
||||
|
||||
DBUtils.HistoryPair[] pairs = DBUtils.getChatHistory( m_activity, m_rowid );
|
||||
if ( null != pairs ) {
|
||||
LinearLayout layout = (LinearLayout)
|
||||
findViewById( R.id.chat_history );
|
||||
Bundle args = getArguments();
|
||||
m_rowid = args.getLong( GameUtils.INTENT_KEY_ROWID, -1 );
|
||||
m_curPlayer = args.getInt( INTENT_KEY_PLAYER, -1 );
|
||||
m_names = args.getStringArray( INTENT_KEY_NAMES );
|
||||
boolean[] locals = args.getBooleanArray( INTENT_KEY_LOCS );
|
||||
|
||||
for ( DBUtils.HistoryPair pair : pairs ) {
|
||||
TextView view = (TextView)
|
||||
inflate( pair.sourceLocal
|
||||
? R.layout.chat_history_local
|
||||
: R.layout.chat_history_remote );
|
||||
view.setText( pair.msg );
|
||||
layout.addView( view );
|
||||
}
|
||||
}
|
||||
|
||||
final ScrollView scroll = (ScrollView)findViewById( R.id.scroll );
|
||||
scroll.post(new Runnable() {
|
||||
m_scroll = (ScrollView)findViewById( R.id.scroll );
|
||||
m_layout = (TableLayout)findViewById( R.id.chat_history );
|
||||
m_layout.addOnLayoutChangeListener( new OnLayoutChangeListener() {
|
||||
@Override
|
||||
public void run() {
|
||||
scroll.fullScroll(View.FOCUS_DOWN);
|
||||
public void onLayoutChange( View vv, int ll, int tt, int rr,
|
||||
int bb, int ol, int ot,
|
||||
int or, int ob ) {
|
||||
scrollDown();
|
||||
}
|
||||
});
|
||||
|
||||
DBUtils.HistoryPair[] pairs
|
||||
= DBUtils.getChatHistory( m_activity, m_rowid, locals );
|
||||
if ( null != pairs ) {
|
||||
for ( DBUtils.HistoryPair pair : pairs ) {
|
||||
addRow( pair.msg, pair.playerIndx );
|
||||
}
|
||||
}
|
||||
// scrollDown();
|
||||
|
||||
String title = getString( R.string.chat_title_fmt,
|
||||
GameUtils.getName( m_activity, m_rowid ) );
|
||||
|
@ -97,10 +114,59 @@ public class ChatDelegate extends DelegateBase {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume()
|
||||
{
|
||||
super.onResume();
|
||||
m_jniThreadRef = JNIThread.getRetained( m_rowid );
|
||||
if ( null == m_jniThreadRef ) {
|
||||
DbgUtils.logf( "ChatDelegate.onResume(): m_jniThreadRef null; exiting" );
|
||||
finish();
|
||||
} else {
|
||||
s_visibleThis = this;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause()
|
||||
{
|
||||
if ( null != m_jniThreadRef ) {
|
||||
m_jniThreadRef.release();
|
||||
}
|
||||
s_visibleThis = null;
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
private void addRow( String msg, int playerIndx )
|
||||
{
|
||||
TableRow row = (TableRow)inflate( R.layout.chat_row );
|
||||
if ( m_curPlayer == playerIndx ) {
|
||||
row.setBackgroundColor(0xFF202020);
|
||||
}
|
||||
TextView view = (TextView)row.findViewById( R.id.chat_row_text );
|
||||
view.setText( msg );
|
||||
view = (TextView)row.findViewById( R.id.chat_row_name );
|
||||
view.setText( getString( R.string.chat_sender_fmt,
|
||||
m_names[playerIndx] ) );
|
||||
m_layout.addView( row );
|
||||
|
||||
scrollDown();
|
||||
}
|
||||
|
||||
private void scrollDown()
|
||||
{
|
||||
m_scroll.post( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
m_scroll.fullScroll( View.FOCUS_DOWN );
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu( Menu menu )
|
||||
{
|
||||
String text = mEdit.getText().toString();
|
||||
String text = m_edit.getText().toString();
|
||||
boolean haveText = null != text && 0 < text.length();
|
||||
Utils.setItemVisible( menu, R.id.chat_menu_send, haveText );
|
||||
return true;
|
||||
|
@ -117,17 +183,26 @@ public class ChatDelegate extends DelegateBase {
|
|||
}
|
||||
break;
|
||||
case R.id.chat_menu_send:
|
||||
String text = mEdit.getText().toString();
|
||||
String text = m_edit.getText().toString();
|
||||
if ( null == text || text.length() == 0 ) {
|
||||
setResult( Activity.RESULT_CANCELED );
|
||||
finish();
|
||||
} else {
|
||||
DBUtils.appendChatHistory( m_activity, m_rowid, text, true );
|
||||
DBUtils.appendChatHistory( m_activity, m_rowid, text, m_curPlayer );
|
||||
addRow( text, m_curPlayer );
|
||||
m_edit.setText( null );
|
||||
|
||||
Intent result = new Intent();
|
||||
result.putExtra( BoardDelegate.INTENT_KEY_CHAT, text );
|
||||
setResult( Activity.RESULT_OK, result );
|
||||
m_jniThreadRef.sendChat( text );
|
||||
// if ( null != jniThread ) {
|
||||
// jniThread.handle( JNIThread.JNICmd.CMD_SENDCHAT, text );
|
||||
// } else {
|
||||
// Intent result = new Intent();
|
||||
// result.putExtra( BoardDelegate.INTENT_KEY_CHAT, text );
|
||||
// setResult( Activity.RESULT_OK, result );
|
||||
// finish();
|
||||
// }
|
||||
}
|
||||
finish();
|
||||
// finish();
|
||||
break;
|
||||
default:
|
||||
handled = false;
|
||||
|
@ -143,8 +218,8 @@ public class ChatDelegate extends DelegateBase {
|
|||
case CLEAR_ACTION:
|
||||
if ( AlertDialog.BUTTON_POSITIVE == which ) {
|
||||
DBUtils.clearChatHistory( m_activity, m_rowid );
|
||||
LinearLayout layout =
|
||||
(LinearLayout)findViewById( R.id.chat_history );
|
||||
TableLayout layout =
|
||||
(TableLayout)findViewById( R.id.chat_history );
|
||||
layout.removeAllViews();
|
||||
}
|
||||
break;
|
||||
|
@ -152,4 +227,37 @@ public class ChatDelegate extends DelegateBase {
|
|||
super.dlgButtonClicked( action, which, params );
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean append( long rowid, String msg, int fromIndx )
|
||||
{
|
||||
boolean handled = null != s_visibleThis
|
||||
&& s_visibleThis.m_rowid == rowid;
|
||||
if ( handled ) {
|
||||
s_visibleThis.addRow( msg, fromIndx );
|
||||
Utils.playNotificationSound( s_visibleThis.m_activity );
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
public static void startForResult( Delegator delegator,
|
||||
RequestCode requestCode,
|
||||
long rowID, int curPlayer,
|
||||
String[] names, boolean[] locs )
|
||||
{
|
||||
Assert.assertFalse( -1 == curPlayer );
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putLong( GameUtils.INTENT_KEY_ROWID, rowID );
|
||||
bundle.putInt( INTENT_KEY_PLAYER, curPlayer );
|
||||
bundle.putStringArray( INTENT_KEY_NAMES, names );
|
||||
bundle.putBooleanArray( INTENT_KEY_LOCS, locs );
|
||||
|
||||
Activity activity = delegator.getActivity();
|
||||
if ( activity instanceof FragActivity ) {
|
||||
FragActivity.addFragment( new ChatFrag(), bundle, delegator );
|
||||
} else {
|
||||
Intent intent = new Intent( activity, ChatActivity.class );
|
||||
intent.putExtras( bundle );
|
||||
activity.startActivityForResult( intent, requestCode.ordinal() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/* -*- compile-command: "find-and-ant.sh debug install"; -*- */
|
||||
/*
|
||||
* Copyright 2016 by Eric House (xwords@eehouse.org). All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package org.eehouse.android.xw4;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
public class ChatFrag extends XWFragment {
|
||||
|
||||
@Override
|
||||
public void onCreate( Bundle sis )
|
||||
{
|
||||
super.onCreate( new ChatDelegate( this, sis ), sis, true );
|
||||
}
|
||||
}
|
|
@ -20,25 +20,23 @@
|
|||
|
||||
package org.eehouse.android.xw4;
|
||||
|
||||
import android.content.Context;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.UnresolvedAddressException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Vector;
|
||||
import java.util.Iterator;
|
||||
import java.util.Vector;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
|
||||
import org.eehouse.android.xw4.jni.*;
|
||||
import org.eehouse.android.xw4.jni.JNIThread.*;
|
||||
import org.eehouse.android.xw4.jni.CurGameInfo.DeviceRole;
|
||||
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
|
||||
import org.eehouse.android.xw4.jni.CurGameInfo.DeviceRole;
|
||||
import org.eehouse.android.xw4.jni.JNIThread.*;
|
||||
|
||||
public class CommsTransport implements TransportProcs,
|
||||
NetStateCache.StateChangedIf {
|
||||
|
@ -49,7 +47,6 @@ public class CommsTransport implements TransportProcs,
|
|||
private JNIThread m_jniThread;
|
||||
private CommsThread m_thread;
|
||||
private TransportProcs.TPMsgHandler m_tpHandler;
|
||||
private Handler m_handler;
|
||||
private boolean m_done = false;
|
||||
|
||||
private Vector<ByteBuffer> m_buffersOut;
|
||||
|
@ -214,10 +211,9 @@ public class CommsTransport implements TransportProcs,
|
|||
} // loop
|
||||
}
|
||||
|
||||
public void setReceiver( JNIThread jnit, Handler handler )
|
||||
public void setReceiver( JNIThread jnit )
|
||||
{
|
||||
m_jniThread = jnit;
|
||||
m_handler = handler;
|
||||
}
|
||||
|
||||
public void waitToStop()
|
||||
|
|
|
@ -385,8 +385,8 @@ public class ConnStatusHandler {
|
|||
String as64 = XWPrefs.getPrefsString( context,
|
||||
R.string.key_connstat_data );
|
||||
if ( null != as64 && 0 < as64.length() ) {
|
||||
byte[] bytes = XwJNI.base64Decode( as64 );
|
||||
try {
|
||||
byte[] bytes = XwJNI.base64Decode( as64 );
|
||||
ObjectInputStream ois =
|
||||
new ObjectInputStream( new ByteArrayInputStream(bytes) );
|
||||
s_records =
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* -*- compile-command: "find-and-ant.sh debug install"; -*- */
|
||||
/*
|
||||
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
|
||||
* Copyright 2009-2016 by Eric House (xwords@eehouse.org). All
|
||||
* rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -42,8 +42,10 @@ public class DBHelper extends SQLiteOpenHelper {
|
|||
public static final String TABLE_NAME_LOC = "loc";
|
||||
public static final String TABLE_NAME_PAIRS = "pairs";
|
||||
public static final String TABLE_NAME_INVITES = "invites";
|
||||
public static final String TABLE_NAME_CHAT = "chat";
|
||||
public static final String TABLE_NAME_LOGS = "logs";
|
||||
private static final String DB_NAME = "xwdb";
|
||||
private static final int DB_VERSION = 25;
|
||||
private static final int DB_VERSION = 27;
|
||||
|
||||
public static final String GAME_NAME = "GAME_NAME";
|
||||
public static final String VISID = "VISID";
|
||||
|
@ -111,6 +113,10 @@ public class DBHelper extends SQLiteOpenHelper {
|
|||
public static final String TARGET = "TARGET";
|
||||
public static final String TIMESTAMP = "TIMESTAMP";
|
||||
|
||||
public static final String SENDER = "SENDER";
|
||||
public static final String MESSAGE = "MESSAGE";
|
||||
public static final String TAG = "TAG";
|
||||
|
||||
private Context m_context;
|
||||
|
||||
private static final String[][] s_summaryColsAndTypes = {
|
||||
|
@ -206,6 +212,18 @@ public class DBHelper extends SQLiteOpenHelper {
|
|||
,{ TIMESTAMP, "DATETIME DEFAULT CURRENT_TIMESTAMP" }
|
||||
};
|
||||
|
||||
private static final String[][] s_chatsSchema = {
|
||||
{ ROW, "INTEGER" }
|
||||
,{ SENDER, "INTEGER" }
|
||||
,{ MESSAGE, "TEXT" }
|
||||
};
|
||||
|
||||
private static final String[][] s_logsSchema = {
|
||||
{ TIMESTAMP, "DATETIME DEFAULT CURRENT_TIMESTAMP" },
|
||||
{ MESSAGE, "TEXT" },
|
||||
{ TAG, "TEXT" },
|
||||
};
|
||||
|
||||
public DBHelper( Context context )
|
||||
{
|
||||
super( context, DB_NAME, null, DB_VERSION );
|
||||
|
@ -230,13 +248,15 @@ public class DBHelper extends SQLiteOpenHelper {
|
|||
createLocTable( db );
|
||||
createPairsTable( db );
|
||||
createInvitesTable( db );
|
||||
createChatsTable( db );
|
||||
createLogsTable( db );
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("fallthrough")
|
||||
public void onUpgrade( SQLiteDatabase db, int oldVersion, int newVersion )
|
||||
{
|
||||
DbgUtils.logf( "onUpgrade: old: %d; new: %d", oldVersion, newVersion );
|
||||
DbgUtils.logf( false, "onUpgrade: old: %d; new: %d", oldVersion, newVersion );
|
||||
|
||||
boolean madeSumTable = false;
|
||||
switch( oldVersion ) {
|
||||
|
@ -297,7 +317,11 @@ public class DBHelper extends SQLiteOpenHelper {
|
|||
}
|
||||
case 24:
|
||||
createInvitesTable( db );
|
||||
|
||||
case 25:
|
||||
createChatsTable( db );
|
||||
case 26:
|
||||
createLogsTable( db );
|
||||
|
||||
break;
|
||||
default:
|
||||
db.execSQL( "DROP TABLE " + TABLE_NAME_SUM + ";" );
|
||||
|
@ -401,6 +425,16 @@ public class DBHelper extends SQLiteOpenHelper {
|
|||
createTable( db, TABLE_NAME_INVITES, s_invitesSchema );
|
||||
}
|
||||
|
||||
private void createChatsTable( SQLiteDatabase db )
|
||||
{
|
||||
createTable( db, TABLE_NAME_CHAT, s_chatsSchema );
|
||||
}
|
||||
|
||||
private void createLogsTable( SQLiteDatabase db )
|
||||
{
|
||||
createTable( db, TABLE_NAME_LOGS, s_logsSchema );
|
||||
}
|
||||
|
||||
// Move all existing games to the row previously named "cur games'
|
||||
private void moveToCurGames( SQLiteDatabase db )
|
||||
{
|
||||
|
@ -426,7 +460,7 @@ public class DBHelper extends SQLiteOpenHelper {
|
|||
db.beginTransaction();
|
||||
try {
|
||||
String query;
|
||||
String[] columnNames = DBUtils.getColumns( db, name );
|
||||
String[] columnNames = getColumns( db, name );
|
||||
if ( null != columnNames ) { // no data means no need to copy
|
||||
query = String.format( "ALTER table %s RENAME TO 'temp_%s'",
|
||||
name, name );
|
||||
|
@ -498,6 +532,15 @@ public class DBHelper extends SQLiteOpenHelper {
|
|||
return result;
|
||||
}
|
||||
|
||||
private static String[] getColumns( SQLiteDatabase db, String name )
|
||||
{
|
||||
String query = String.format( "SELECT * FROM %s LIMIT 1", name );
|
||||
Cursor cursor = db.rawQuery( query, null );
|
||||
String[] colNames = cursor.getColumnNames();
|
||||
cursor.close();
|
||||
return colNames;
|
||||
}
|
||||
|
||||
private class TableAndVersion {
|
||||
public String name;
|
||||
public int addedVersion;
|
||||
|
|
|
@ -67,6 +67,9 @@ public class DBUtils {
|
|||
public static final int GROUPID_UNSPEC = -1;
|
||||
public static final String KEY_NEWGAMECOUNT = "DBUtils.newGameCount";
|
||||
|
||||
// how many log rows to keep? (0 means off)
|
||||
private static final int LOGLIMIT = 0;
|
||||
|
||||
private static final String DICTS_SEP = ",";
|
||||
|
||||
private static final String ROW_ID = "rowid";
|
||||
|
@ -96,13 +99,13 @@ public class DBUtils {
|
|||
}
|
||||
|
||||
public static class HistoryPair {
|
||||
private HistoryPair( String p_msg, boolean p_sourceLocal )
|
||||
private HistoryPair( String p_msg, int p_playerIndx )
|
||||
{
|
||||
msg = p_msg;
|
||||
sourceLocal = p_sourceLocal;
|
||||
playerIndx = p_playerIndx;
|
||||
}
|
||||
String msg;
|
||||
boolean sourceLocal;
|
||||
int playerIndx;
|
||||
}
|
||||
|
||||
public static class DictBrowseState {
|
||||
|
@ -118,10 +121,14 @@ public class DBUtils {
|
|||
long maxMillis )
|
||||
{
|
||||
GameSummary result = null;
|
||||
GameLock lock = new GameLock( rowid, false ).lock( maxMillis );
|
||||
if ( null != lock ) {
|
||||
result = getSummary( context, lock );
|
||||
lock.unlock();
|
||||
try {
|
||||
GameLock lock = new GameLock( rowid, false ).lock( maxMillis );
|
||||
if ( null != lock ) {
|
||||
result = getSummary( context, lock );
|
||||
lock.unlock();
|
||||
}
|
||||
} catch ( GameLock.GameLockedException gle ) {
|
||||
DbgUtils.loge( gle );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -595,7 +602,7 @@ public class DBUtils {
|
|||
|
||||
}
|
||||
|
||||
private static void setInt( long rowid, String column, int value )
|
||||
private static void setSummaryInt( long rowid, String column, int value )
|
||||
{
|
||||
ContentValues values = new ContentValues();
|
||||
values.put( column, value );
|
||||
|
@ -604,13 +611,13 @@ public class DBUtils {
|
|||
|
||||
public static void setMsgFlags( long rowid, int flags )
|
||||
{
|
||||
setInt( rowid, DBHelper.HASMSGS, flags );
|
||||
setSummaryInt( rowid, DBHelper.HASMSGS, flags );
|
||||
notifyListeners( rowid, GameChangeType.GAME_CHANGED );
|
||||
}
|
||||
|
||||
public static void setExpanded( long rowid, boolean expanded )
|
||||
{
|
||||
setInt( rowid, DBHelper.CONTRACTED, expanded?0:1 );
|
||||
setSummaryInt( rowid, DBHelper.CONTRACTED, expanded?0:1 );
|
||||
}
|
||||
|
||||
private static int getInt( Context context, long rowid, String column,
|
||||
|
@ -1107,8 +1114,9 @@ public class DBUtils {
|
|||
public static void deleteGame( Context context, GameLock lock )
|
||||
{
|
||||
Assert.assertTrue( lock.canWrite() );
|
||||
String selSummaries = String.format( ROW_ID_FMT, lock.getRowid() );
|
||||
String selInvites = String.format( "%s=%d", DBHelper.ROW, lock.getRowid() );
|
||||
long rowid = lock.getRowid();
|
||||
String selSummaries = String.format( ROW_ID_FMT, rowid );
|
||||
String selInvites = String.format( "%s=%d", DBHelper.ROW, rowid );
|
||||
|
||||
initDB( context );
|
||||
synchronized( s_dbHelper ) {
|
||||
|
@ -1117,6 +1125,9 @@ public class DBUtils {
|
|||
|
||||
// Delete invitations too
|
||||
db.delete( DBHelper.TABLE_NAME_INVITES, selInvites, null );
|
||||
|
||||
// Delete chats too -- same sel as for invites
|
||||
db.delete( DBHelper.TABLE_NAME_CHAT, selInvites, null );
|
||||
|
||||
db.close();
|
||||
}
|
||||
|
@ -1176,21 +1187,92 @@ public class DBUtils {
|
|||
updateRow( context, DBHelper.TABLE_NAME_SUM, rowid, values );
|
||||
}
|
||||
|
||||
public static HistoryPair[] getChatHistory( Context context, long rowid )
|
||||
private static HistoryPair[] convertChatString( Context context, long rowid,
|
||||
boolean[] playersLocal )
|
||||
{
|
||||
HistoryPair[] result = null;
|
||||
String oldHistory = getChatHistoryStr( context, rowid );
|
||||
if ( null != oldHistory ) {
|
||||
DbgUtils.logdf( "convertChatString(): got string: %s", oldHistory );
|
||||
|
||||
ArrayList<ContentValues> valuess = new ArrayList<ContentValues>();
|
||||
ArrayList<HistoryPair> pairs = new ArrayList<HistoryPair>();
|
||||
String localPrefix = LocUtils.getString( context, R.string.chat_local_id );
|
||||
String rmtPrefix = LocUtils.getString( context, R.string.chat_other_id );
|
||||
DbgUtils.logdf( "convertChatString(): prefixes: \"%s\" and \"%s\"", localPrefix, rmtPrefix );
|
||||
String[] msgs = oldHistory.split( "\n" );
|
||||
DbgUtils.logdf( "convertChatString(): split into %d", msgs.length );
|
||||
int localPlayerIndx = -1;
|
||||
int remotePlayerIndx = -1;
|
||||
for ( int ii = playersLocal.length - 1; ii >= 0; --ii ) {
|
||||
if ( playersLocal[ii] ) {
|
||||
localPlayerIndx = ii;
|
||||
} else {
|
||||
remotePlayerIndx = ii;
|
||||
}
|
||||
}
|
||||
for ( String msg : msgs ) {
|
||||
DbgUtils.logdf( "convertChatString(): msg: %s", msg );
|
||||
int indx = -1;
|
||||
String prefix = null;
|
||||
if ( msg.startsWith( localPrefix ) ) {
|
||||
DbgUtils.logdf( "convertChatString(): msg: %s starts with %s", msg, localPrefix );
|
||||
prefix = localPrefix;
|
||||
indx = localPlayerIndx;
|
||||
} else if ( msg.startsWith( rmtPrefix ) ) {
|
||||
DbgUtils.logdf( "convertChatString(): msg: %s starts with %s", msg, rmtPrefix );
|
||||
prefix = rmtPrefix;
|
||||
indx = remotePlayerIndx;
|
||||
} else {
|
||||
DbgUtils.logdf( "convertChatString(): msg: %s starts with neither", msg );
|
||||
}
|
||||
if ( -1 != indx ) {
|
||||
DbgUtils.logdf( "convertChatString(): removing substring %s; was: %s", prefix, msg );
|
||||
msg = msg.substring( prefix.length(), msg.length() );
|
||||
DbgUtils.logdf( "convertChatString(): removED substring; now %s", msg );
|
||||
valuess.add( cvForChat( rowid, msg, indx ) );
|
||||
|
||||
HistoryPair pair = new HistoryPair(msg, indx );
|
||||
pairs.add( pair );
|
||||
}
|
||||
}
|
||||
result = pairs.toArray( new HistoryPair[pairs.size()] );
|
||||
|
||||
appendChatHistory( context, valuess );
|
||||
// clearChatHistoryString( context, rowid );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static HistoryPair[] getChatHistory( Context context, long rowid,
|
||||
boolean[] playersLocal )
|
||||
{
|
||||
HistoryPair[] result = null;
|
||||
if ( BuildConstants.CHAT_SUPPORTED ) {
|
||||
final String localPrefix =
|
||||
LocUtils.getString( context, R.string.chat_local_id );
|
||||
String history = getChatHistoryStr( context, rowid );
|
||||
if ( null != history ) {
|
||||
String[] msgs = history.split( "\n" );
|
||||
result = new HistoryPair[msgs.length];
|
||||
for ( int ii = 0; ii < result.length; ++ii ) {
|
||||
String msg = msgs[ii];
|
||||
boolean isLocal = msg.startsWith( localPrefix );
|
||||
result[ii] = new HistoryPair( msg, isLocal );
|
||||
String[] columns = { DBHelper.SENDER, DBHelper.MESSAGE };
|
||||
String selection = String.format( "%s=%d", DBHelper.ROW, rowid );
|
||||
initDB( context );
|
||||
synchronized( s_dbHelper ) {
|
||||
SQLiteDatabase db = s_dbHelper.getReadableDatabase();
|
||||
Cursor cursor = db.query( DBHelper.TABLE_NAME_CHAT, columns,
|
||||
selection, null, null, null, null );
|
||||
if ( 0 < cursor.getCount() ) {
|
||||
result = new HistoryPair[cursor.getCount()];
|
||||
int msgIndex = cursor.getColumnIndex( DBHelper.MESSAGE );
|
||||
int plyrIndex = cursor.getColumnIndex( DBHelper.SENDER );
|
||||
for ( int ii = 0; cursor.moveToNext(); ++ii ) {
|
||||
String msg = cursor.getString( msgIndex );
|
||||
int plyr = cursor.getInt( plyrIndex );
|
||||
HistoryPair pair = new HistoryPair(msg, plyr );
|
||||
result[ii] = pair;
|
||||
}
|
||||
}
|
||||
cursor.close();
|
||||
db.close();
|
||||
}
|
||||
|
||||
if ( null == result ) {
|
||||
result = convertChatString( context, rowid, playersLocal );
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -1674,26 +1756,57 @@ public class DBUtils {
|
|||
return result;
|
||||
}
|
||||
|
||||
public static void appendChatHistory( Context context, long rowid,
|
||||
String msg, boolean local )
|
||||
private static void appendChatHistory( Context context,
|
||||
ArrayList<ContentValues> valuess )
|
||||
{
|
||||
if ( BuildConstants.CHAT_SUPPORTED ) {
|
||||
Assert.assertNotNull( msg );
|
||||
int id = local ? R.string.chat_local_id : R.string.chat_other_id;
|
||||
msg = LocUtils.getString( context, id ) + msg;
|
||||
|
||||
String cur = getChatHistoryStr( context, rowid );
|
||||
if ( null != cur ) {
|
||||
msg = cur + "\n" + msg;
|
||||
initDB( context );
|
||||
synchronized( s_dbHelper ) {
|
||||
SQLiteDatabase db = s_dbHelper.getWritableDatabase();
|
||||
for ( ContentValues values : valuess ) {
|
||||
db.insert( DBHelper.TABLE_NAME_CHAT, null, values );
|
||||
}
|
||||
|
||||
saveChatHistory( context, rowid, msg );
|
||||
db.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static ContentValues cvForChat( long rowid, String msg, int plyr )
|
||||
{
|
||||
ContentValues values = new ContentValues();
|
||||
values.put( DBHelper.ROW, rowid );
|
||||
values.put( DBHelper.MESSAGE, msg );
|
||||
values.put( DBHelper.SENDER, plyr );
|
||||
return values;
|
||||
}
|
||||
|
||||
public static void appendChatHistory( Context context, long rowid,
|
||||
String msg, int fromPlayer )
|
||||
{
|
||||
Assert.assertNotNull( msg );
|
||||
Assert.assertFalse( -1 == fromPlayer );
|
||||
ArrayList<ContentValues> valuess = new ArrayList<ContentValues>();
|
||||
valuess.add( cvForChat( rowid, msg, fromPlayer ) );
|
||||
appendChatHistory( context, valuess );
|
||||
DbgUtils.logf( "appendChatHistory: inserted \"%s\" from player %d",
|
||||
msg, fromPlayer );
|
||||
} // appendChatHistory
|
||||
|
||||
public static void clearChatHistory( Context context, long rowid )
|
||||
{
|
||||
saveChatHistory( context, rowid, null );
|
||||
String selection = String.format( "%s = %d", DBHelper.ROW, rowid );
|
||||
initDB( context );
|
||||
synchronized( s_dbHelper ) {
|
||||
SQLiteDatabase db = s_dbHelper.getWritableDatabase();
|
||||
db.delete( DBHelper.TABLE_NAME_CHAT, selection, null );
|
||||
|
||||
// for now, remove any old-format history too. Later when it's
|
||||
// removed once converted (after that process is completely
|
||||
// debugged), this can be removed.
|
||||
ContentValues values = new ContentValues();
|
||||
values.putNull( DBHelper.CHAT_HISTORY );
|
||||
updateRowImpl( db, DBHelper.TABLE_NAME_SUM, rowid, values );
|
||||
|
||||
db.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static void setDBChangeListener( DBChangeListener listener )
|
||||
|
@ -1960,15 +2073,6 @@ public class DBUtils {
|
|||
return exists;
|
||||
}
|
||||
|
||||
public static String[] getColumns( SQLiteDatabase db, String name )
|
||||
{
|
||||
String query = String.format( "SELECT * FROM %s LIMIT 1", name );
|
||||
Cursor cursor = db.rawQuery( query, null );
|
||||
String[] colNames = cursor.getColumnNames();
|
||||
cursor.close();
|
||||
return colNames;
|
||||
}
|
||||
|
||||
public static void addToStudyList( Context context, String word,
|
||||
int lang )
|
||||
{
|
||||
|
@ -2304,6 +2408,37 @@ public class DBUtils {
|
|||
return bytes;
|
||||
}
|
||||
|
||||
public static void appendLog( String tag, String msg )
|
||||
{
|
||||
Context context = XWApp.getContext();
|
||||
if ( null != context ) {
|
||||
appendLog( context, msg );
|
||||
}
|
||||
}
|
||||
|
||||
private static void appendLog( Context context, String msg )
|
||||
{
|
||||
if ( 0 < LOGLIMIT ) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put( DBHelper.MESSAGE, msg );
|
||||
|
||||
initDB( context );
|
||||
synchronized( s_dbHelper ) {
|
||||
SQLiteDatabase db = s_dbHelper.getWritableDatabase();
|
||||
long rowid = db.insert( DBHelper.TABLE_NAME_LOGS, null, values );
|
||||
|
||||
if ( 0 == (rowid % (LOGLIMIT / 10)) ) {
|
||||
String where =
|
||||
String.format( "not rowid in (select rowid from %s order by TIMESTAMP desc limit %d)",
|
||||
DBHelper.TABLE_NAME_LOGS, LOGLIMIT );
|
||||
int nGone = db.delete( DBHelper.TABLE_NAME_LOGS, where, null );
|
||||
DbgUtils.logf( false, "appendLog(): deleted %d rows", nGone );
|
||||
}
|
||||
db.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void copyGameDB( Context context, boolean toSDCard )
|
||||
{
|
||||
String name = DBHelper.getDBName();
|
||||
|
@ -2338,20 +2473,12 @@ public class DBUtils {
|
|||
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,
|
||||
String history )
|
||||
{
|
||||
ContentValues values = new ContentValues();
|
||||
if ( null != history ) {
|
||||
values.put( DBHelper.CHAT_HISTORY, history );
|
||||
} else {
|
||||
values.putNull( DBHelper.CHAT_HISTORY );
|
||||
}
|
||||
values.put( DBHelper.LASTPLAY_TIME, new Date().getTime() );
|
||||
updateRow( context, DBHelper.TABLE_NAME_SUM, rowid, values );
|
||||
}
|
||||
// private static void clearChatHistoryString( Context context, long rowid )
|
||||
// {
|
||||
// ContentValues values = new ContentValues();
|
||||
// values.putNull( DBHelper.CHAT_HISTORY );
|
||||
// updateRow( context, DBHelper.TABLE_NAME_SUM, rowid, values );
|
||||
// }
|
||||
|
||||
private static void initDB( Context context )
|
||||
{
|
||||
|
@ -2363,16 +2490,21 @@ public class DBUtils {
|
|||
}
|
||||
}
|
||||
|
||||
private static int updateRowImpl( SQLiteDatabase db, String table,
|
||||
long rowid, ContentValues values )
|
||||
{
|
||||
String selection = String.format( ROW_ID_FMT, rowid );
|
||||
return db.update( table, values, selection, null );
|
||||
}
|
||||
|
||||
|
||||
private static void updateRow( Context context, String table,
|
||||
long rowid, ContentValues values )
|
||||
{
|
||||
String selection = String.format( ROW_ID_FMT, rowid );
|
||||
|
||||
initDB( context );
|
||||
synchronized( s_dbHelper ) {
|
||||
SQLiteDatabase db = s_dbHelper.getWritableDatabase();
|
||||
|
||||
int result = db.update( table, values, selection, null );
|
||||
int result = updateRowImpl( db, table, rowid, values );
|
||||
db.close();
|
||||
if ( 0 == result ) {
|
||||
DbgUtils.logf( "updateRow failed" );
|
||||
|
|
|
@ -26,6 +26,7 @@ import android.content.Intent;
|
|||
import android.content.SharedPreferences;
|
||||
import android.database.Cursor;
|
||||
import android.database.DatabaseUtils;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Looper;
|
||||
import android.preference.PreferenceManager;
|
||||
|
@ -60,21 +61,40 @@ public class DbgUtils {
|
|||
logEnable( on );
|
||||
}
|
||||
|
||||
public static void logf( String msg )
|
||||
public static void logf( String msg )
|
||||
{
|
||||
logf( true, msg );
|
||||
}
|
||||
|
||||
public static void logf( boolean persist, String msg )
|
||||
{
|
||||
if ( s_doLog ) {
|
||||
s_time.setToNow();
|
||||
String time = s_time.format("[%H:%M:%S]");
|
||||
String time = "";
|
||||
// No need for timestamp on marshmallow, as the OS provides it
|
||||
if ( true /*Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1*/ ) {
|
||||
s_time.setToNow();
|
||||
time = s_time.format("[%H:%M:%S]-");
|
||||
}
|
||||
long id = Thread.currentThread().getId();
|
||||
Log.d( TAG, time + "-" + id + "-" + msg );
|
||||
msg = time + id + "-" + msg;
|
||||
Log.d( TAG, msg );
|
||||
|
||||
if ( persist && BuildConfig.DEBUG ) {
|
||||
DBUtils.appendLog( TAG, msg );
|
||||
}
|
||||
}
|
||||
} // logf
|
||||
|
||||
public static void logf( String format, Object... args )
|
||||
{
|
||||
logf( true, format, args );
|
||||
}
|
||||
|
||||
public static void logf( boolean persist, String format, Object... args )
|
||||
{
|
||||
if ( s_doLog ) {
|
||||
Formatter formatter = new Formatter();
|
||||
logf( formatter.format( format, args ).toString() );
|
||||
logf( persist, formatter.format( format, args ).toString() );
|
||||
}
|
||||
} // logf
|
||||
|
||||
|
|
|
@ -19,14 +19,15 @@
|
|||
|
||||
package org.eehouse.android.xw4;
|
||||
|
||||
import android.view.ContextMenu;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.graphics.Rect;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface.OnCancelListener;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
|
@ -55,6 +56,7 @@ public class DelegateBase implements DlgClickNotify,
|
|||
private int m_optionsMenuID;
|
||||
private int m_layoutID;
|
||||
private View m_rootView;
|
||||
private boolean m_isVisible;
|
||||
|
||||
public DelegateBase( Delegator delegator, Bundle bundle, int layoutID )
|
||||
{
|
||||
|
@ -86,6 +88,23 @@ public class DelegateBase implements DlgClickNotify,
|
|||
protected void onDestroy() {}
|
||||
protected void onWindowFocusChanged( boolean hasFocus ) {}
|
||||
protected boolean onBackPressed() { return false; }
|
||||
public void orientationChanged() {}
|
||||
|
||||
protected void requestWindowFeature( int feature ) {}
|
||||
|
||||
// Fragments only
|
||||
protected View inflateView( LayoutInflater inflater, ViewGroup container )
|
||||
{
|
||||
View view = null;
|
||||
int layoutID = getLayoutID();
|
||||
if ( 0 < layoutID ) {
|
||||
view = inflater.inflate( layoutID, container, false );
|
||||
LocUtils.xlateView( m_activity, view );
|
||||
setContentView( view );
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
protected void onActivityResult( RequestCode requestCode, int resultCode,
|
||||
Intent data )
|
||||
{
|
||||
|
@ -94,11 +113,13 @@ public class DelegateBase implements DlgClickNotify,
|
|||
|
||||
protected void onResume()
|
||||
{
|
||||
m_isVisible = true;
|
||||
XWService.setListener( this );
|
||||
}
|
||||
|
||||
protected void onPause()
|
||||
{
|
||||
m_isVisible = false;
|
||||
XWService.setListener( null );
|
||||
}
|
||||
|
||||
|
@ -131,6 +152,8 @@ public class DelegateBase implements DlgClickNotify,
|
|||
return m_activity.getIntent();
|
||||
}
|
||||
|
||||
protected Delegator getDelegator() { return m_delegator; }
|
||||
|
||||
protected int getLayoutID()
|
||||
{
|
||||
return m_layoutID;
|
||||
|
@ -187,7 +210,11 @@ public class DelegateBase implements DlgClickNotify,
|
|||
|
||||
protected void setResult( int result, Intent intent )
|
||||
{
|
||||
m_activity.setResult( result, intent );
|
||||
if ( m_activity instanceof FragActivity ) {
|
||||
Assert.fail();
|
||||
} else {
|
||||
m_activity.setResult( result, intent );
|
||||
}
|
||||
}
|
||||
|
||||
protected void setResult( int result )
|
||||
|
@ -207,7 +234,34 @@ public class DelegateBase implements DlgClickNotify,
|
|||
|
||||
protected void finish()
|
||||
{
|
||||
m_activity.finish();
|
||||
if ( m_activity instanceof FragActivity ) {
|
||||
((FragActivity)m_activity).finishFragment();
|
||||
} else {
|
||||
m_activity.finish();
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isPortrait()
|
||||
{
|
||||
int[] containerDims = getContainerDims( new int[2] );
|
||||
boolean result = containerDims[0] < containerDims[1];
|
||||
DbgUtils.logdf( "%s.isPortrait() => %b", getClass().getName(), result );
|
||||
return result;
|
||||
}
|
||||
|
||||
protected int[] getContainerDims( int[] outDims )
|
||||
{
|
||||
if ( m_activity instanceof FragActivity ) {
|
||||
((FragActivity)m_activity).getFragmentDims( outDims );
|
||||
} else {
|
||||
Rect rect = new Rect();
|
||||
m_rootView.getWindowVisibleDisplayFrame( rect );
|
||||
outDims[0] = rect.width();
|
||||
outDims[1] = rect.height();
|
||||
}
|
||||
DbgUtils.logdf( "%s.getContainerDims(): width => %d, height => %d",
|
||||
getClass().getName(), outDims[0], outDims[1] );
|
||||
return outDims;
|
||||
}
|
||||
|
||||
protected String getString( int resID, Object... params )
|
||||
|
@ -523,6 +577,8 @@ public class DelegateBase implements DlgClickNotify,
|
|||
{
|
||||
m_dlgDelegate.showSMSEnableDialog( action, params );
|
||||
}
|
||||
|
||||
protected boolean isVisible() { return m_isVisible; }
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// MultiService.MultiEventListener interface
|
||||
|
@ -541,7 +597,7 @@ public class DelegateBase implements DlgClickNotify,
|
|||
case BAD_PROTO_SMS:
|
||||
fmtId = R.string.sms_bad_proto_fmt;
|
||||
break;
|
||||
case APP_NOT_FOUND:
|
||||
case APP_NOT_FOUND_BT:
|
||||
fmtId = R.string.app_not_found_fmt;
|
||||
break;
|
||||
case RELAY_ALERT:
|
||||
|
|
|
@ -163,14 +163,15 @@ public class DictBrowseDelegate extends ListDelegateBase
|
|||
|
||||
protected void init( Bundle savedInstanceState )
|
||||
{
|
||||
Intent intent = getIntent();
|
||||
String name = null == intent? null:intent.getStringExtra( DICT_NAME );
|
||||
Bundle args = getArguments();
|
||||
String name = null == args? null : args.getString( DICT_NAME );
|
||||
Assert.assertNotNull( name );
|
||||
if ( null == name ) {
|
||||
finish();
|
||||
} else {
|
||||
m_name = name;
|
||||
m_loc =
|
||||
DictUtils.DictLoc.values()[intent.getIntExtra( DICT_LOC, 0 )];
|
||||
DictUtils.DictLoc.values()[args.getInt( DICT_LOC, 0 )];
|
||||
m_lang = DictLangCache.getDictLangCode( m_activity, name );
|
||||
|
||||
String[] names = { name };
|
||||
|
@ -363,9 +364,9 @@ public class DictBrowseDelegate extends ListDelegateBase
|
|||
DBUtils.dictsSetOffset( m_activity, m_name, m_loc, m_browseState );
|
||||
m_browseState = null;
|
||||
|
||||
startActivity( getIntent() );
|
||||
finish(); // pop fragment stack before adding new (only it doesn't work)
|
||||
|
||||
finish();
|
||||
launch( getDelegator(), getArguments() );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -421,19 +422,31 @@ public class DictBrowseDelegate extends ListDelegateBase
|
|||
m_maxSpinner.setOnItemSelectedListener( this );
|
||||
}
|
||||
|
||||
private static void launch( Delegator delegator, Bundle bundle )
|
||||
{
|
||||
Activity activity = delegator.getActivity();
|
||||
if ( activity instanceof FragActivity ) {
|
||||
FragActivity.addFragment( new DictBrowseFrag(), bundle, delegator );
|
||||
} else {
|
||||
Intent intent = new Intent( activity, DictBrowseActivity.class );
|
||||
intent.putExtras( bundle );
|
||||
activity.startActivity( intent );
|
||||
}
|
||||
}
|
||||
|
||||
public static void launch( Context caller, String name,
|
||||
public static void launch( Delegator delegator, String name,
|
||||
DictUtils.DictLoc loc )
|
||||
{
|
||||
Intent intent = new Intent( caller, DictBrowseActivity.class );
|
||||
intent.putExtra( DICT_NAME, name );
|
||||
intent.putExtra( DICT_LOC, loc.ordinal() );
|
||||
caller.startActivity( intent );
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString( DICT_NAME, name );
|
||||
bundle.putInt( DICT_LOC, loc.ordinal() );
|
||||
launch( delegator, bundle );
|
||||
}
|
||||
|
||||
public static void launch( Context caller, String name )
|
||||
public static void launch( Delegator delegator, String name )
|
||||
{
|
||||
DictUtils.DictLoc loc = DictUtils.getDictLoc( caller, name );
|
||||
launch( caller, name, loc );
|
||||
DictUtils.DictLoc loc
|
||||
= DictUtils.getDictLoc( delegator.getActivity(), name );
|
||||
launch( delegator, name, loc );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/* -*- compile-command: "find-and-ant.sh debug install"; -*- */
|
||||
/*
|
||||
* Copyright 2016 by Eric House (xwords@eehouse.org). All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package org.eehouse.android.xw4;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
public class DictBrowseFrag extends XWFragment {
|
||||
|
||||
@Override
|
||||
public void onCreate( Bundle sis )
|
||||
{
|
||||
super.onCreate( new DictBrowseDelegate( this, sis ), sis, true );
|
||||
}
|
||||
}
|
|
@ -26,7 +26,6 @@ import android.os.Bundle;
|
|||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.PopupMenu;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
|
@ -35,11 +34,6 @@ import org.eehouse.android.xw4.loc.LocUtils;
|
|||
|
||||
public class DictsActivity extends XWActivity {
|
||||
|
||||
private static interface SafePopup {
|
||||
public void doPopup( Context context, View button,
|
||||
String curDict, int lang );
|
||||
}
|
||||
private static SafePopup s_safePopup = null;
|
||||
// I can't provide a subclass of MenuItem to hold DictAndLoc, so
|
||||
// settle for a hash on the side.
|
||||
private DictsDelegate m_dlgt;
|
||||
|
@ -51,71 +45,6 @@ public class DictsActivity extends XWActivity {
|
|||
super.onCreate( savedInstanceState, m_dlgt );
|
||||
} // onCreate
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if ( !m_dlgt.onBackPressed() ) {
|
||||
super.onBackPressed();
|
||||
}
|
||||
}
|
||||
|
||||
private static class SafePopupImpl implements SafePopup {
|
||||
public void doPopup( final Context context, View button,
|
||||
String curDict, int lang ) {
|
||||
|
||||
final HashMap<MenuItem, DictAndLoc> itemData
|
||||
= new HashMap<MenuItem, DictAndLoc>();
|
||||
|
||||
MenuItem.OnMenuItemClickListener listener =
|
||||
new MenuItem.OnMenuItemClickListener() {
|
||||
public boolean onMenuItemClick( MenuItem item )
|
||||
{
|
||||
DictAndLoc dal = itemData.get( item );
|
||||
|
||||
DictBrowseDelegate.launch( context, dal.name,
|
||||
dal.loc );
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
PopupMenu popup = new PopupMenu( context, button );
|
||||
Menu menu = popup.getMenu();
|
||||
|
||||
// Add at top but save until have dal info
|
||||
MenuItem curItem =
|
||||
menu.add( LocUtils.getString( context,
|
||||
R.string.cur_menu_marker_fmt,
|
||||
curDict ) );
|
||||
|
||||
DictAndLoc[] dals = DictLangCache.getDALsHaveLang( context, lang );
|
||||
for ( DictAndLoc dal : dals ) {
|
||||
MenuItem item = dal.name.equals(curDict)
|
||||
? curItem : menu.add( dal.name );
|
||||
item.setOnMenuItemClickListener( listener );
|
||||
itemData.put( item, dal );
|
||||
}
|
||||
|
||||
popup.show();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean handleDictsPopup( Context context, View button,
|
||||
String curDict, int lang )
|
||||
{
|
||||
int nDicts = DictLangCache.getLangCount( context, lang );
|
||||
if ( null == s_safePopup && 1 < nDicts ) {
|
||||
int sdkVersion = Integer.valueOf( android.os.Build.VERSION.SDK );
|
||||
if ( 11 <= sdkVersion ) {
|
||||
s_safePopup = new SafePopupImpl();
|
||||
}
|
||||
}
|
||||
|
||||
boolean canHandle = null != s_safePopup && 1 < nDicts;
|
||||
if ( canHandle ) {
|
||||
s_safePopup.doPopup( context, button, curDict, lang );
|
||||
}
|
||||
return canHandle;
|
||||
}
|
||||
|
||||
public static void start( Context context )
|
||||
{
|
||||
Intent intent = new Intent( context, DictsActivity.class );
|
||||
|
|
|
@ -44,6 +44,7 @@ import android.widget.Button;
|
|||
import android.widget.CheckBox;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListView;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.net.HttpURLConnection;
|
||||
|
@ -107,6 +108,53 @@ public class DictsDelegate extends ListDelegateBase
|
|||
private String m_lastDict;
|
||||
private String m_noteNone;
|
||||
|
||||
private static interface SafePopup {
|
||||
public void doPopup( Delegator dlgtor, View button,
|
||||
String curDict, int lang );
|
||||
}
|
||||
private static SafePopup s_safePopup = null;
|
||||
|
||||
private static class SafePopupImpl implements SafePopup {
|
||||
public void doPopup( final Delegator dlgtor, View button,
|
||||
String curDict, int lang ) {
|
||||
|
||||
final HashMap<MenuItem, DictAndLoc> itemData
|
||||
= new HashMap<MenuItem, DictAndLoc>();
|
||||
|
||||
MenuItem.OnMenuItemClickListener listener =
|
||||
new MenuItem.OnMenuItemClickListener() {
|
||||
public boolean onMenuItemClick( MenuItem item )
|
||||
{
|
||||
DictAndLoc dal = itemData.get( item );
|
||||
|
||||
DictBrowseDelegate.launch( dlgtor, dal.name,
|
||||
dal.loc );
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
Context context = dlgtor.getActivity();
|
||||
PopupMenu popup = new PopupMenu( context, button );
|
||||
Menu menu = popup.getMenu();
|
||||
|
||||
// Add at top but save until have dal info
|
||||
MenuItem curItem =
|
||||
menu.add( LocUtils.getString( context,
|
||||
R.string.cur_menu_marker_fmt,
|
||||
curDict ) );
|
||||
|
||||
DictAndLoc[] dals = DictLangCache.getDALsHaveLang( context, lang );
|
||||
for ( DictAndLoc dal : dals ) {
|
||||
MenuItem item = dal.name.equals(curDict)
|
||||
? curItem : menu.add( dal.name );
|
||||
item.setOnMenuItemClickListener( listener );
|
||||
itemData.put( item, dal );
|
||||
}
|
||||
|
||||
popup.show();
|
||||
}
|
||||
}
|
||||
|
||||
private static class DictInfo implements Comparable {
|
||||
public String m_name;
|
||||
public String m_lang;
|
||||
|
@ -518,7 +566,7 @@ public class DictsDelegate extends ListDelegateBase
|
|||
switchShowingRemote( m_checkbox.isChecked() );
|
||||
} else {
|
||||
XWListItem item = (XWListItem)view;
|
||||
DictBrowseDelegate.launch( m_activity, item.getText(),
|
||||
DictBrowseDelegate.launch( getDelegator(), item.getText(),
|
||||
(DictLoc)item.getCached() );
|
||||
}
|
||||
}
|
||||
|
@ -1017,6 +1065,25 @@ public class DictsDelegate extends ListDelegateBase
|
|||
new GetDefaultDictTask( context, lc, lstnr ).execute();
|
||||
}
|
||||
|
||||
public static boolean handleDictsPopup( Delegator delegator, View button,
|
||||
String curDict, int lang )
|
||||
{
|
||||
Context context = delegator.getActivity();
|
||||
int nDicts = DictLangCache.getLangCount( context, lang );
|
||||
if ( null == s_safePopup && 1 < nDicts ) {
|
||||
int sdkVersion = Integer.valueOf( android.os.Build.VERSION.SDK );
|
||||
if ( 11 <= sdkVersion ) {
|
||||
s_safePopup = new SafePopupImpl();
|
||||
}
|
||||
}
|
||||
|
||||
boolean canHandle = null != s_safePopup && 1 < nDicts;
|
||||
if ( canHandle ) {
|
||||
s_safePopup.doPopup( delegator, button, curDict, lang );
|
||||
}
|
||||
return canHandle;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// XWListItem.ExpandedListener interface
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -38,11 +38,13 @@ import android.widget.Spinner;
|
|||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.text.DateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
|
@ -153,6 +155,8 @@ public class DlgDelegate {
|
|||
void showNotAgainDlgThen( int msgID, int prefsKey, Action action );
|
||||
}
|
||||
|
||||
private static Map<Integer, WeakReference<DelegateBase>> s_pendings
|
||||
= new HashMap<Integer, WeakReference<DelegateBase>>();
|
||||
private Activity m_activity;
|
||||
private DelegateBase m_dlgt;
|
||||
private DlgClickNotify m_clickCallback;
|
||||
|
@ -201,8 +205,12 @@ public class DlgDelegate {
|
|||
|
||||
protected void showDialog( DlgID dlgID )
|
||||
{
|
||||
int id = dlgID.ordinal();
|
||||
if ( m_activity instanceof FragActivity ) {
|
||||
s_pendings.put( id, new WeakReference<DelegateBase>(m_dlgt) );
|
||||
}
|
||||
if ( !m_activity.isFinishing() ) {
|
||||
m_activity.showDialog( dlgID.ordinal() );
|
||||
m_activity.showDialog( id );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -872,6 +880,26 @@ public class DlgDelegate {
|
|||
m_dlgStates.put( state.m_id, state );
|
||||
}
|
||||
|
||||
public static Dialog onCreateDialog( int id )
|
||||
{
|
||||
Dialog result = null;
|
||||
WeakReference<DelegateBase> ref = s_pendings.get( id );
|
||||
DelegateBase dlgt = ref.get();
|
||||
if ( null != dlgt ) {
|
||||
result = dlgt.onCreateDialog( id );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void onPrepareDialog( int id, Dialog dialog )
|
||||
{
|
||||
WeakReference<DelegateBase> ref = s_pendings.get( id );
|
||||
DelegateBase dlgt = ref.get();
|
||||
if ( null != dlgt ) {
|
||||
dlgt.prepareDialog( DlgID.values()[id], dialog );
|
||||
}
|
||||
}
|
||||
|
||||
private String getString( int id, Object... params )
|
||||
{
|
||||
return m_dlgt.getString( id, params );
|
||||
|
|
|
@ -30,7 +30,10 @@ public class DwnldActivity extends XWActivity {
|
|||
protected void onCreate( Bundle savedInstanceState )
|
||||
{
|
||||
requestWindowFeature( Window.FEATURE_NO_TITLE );
|
||||
|
||||
requestWindowFeature( Window.FEATURE_LEFT_ICON );
|
||||
getWindow().setFeatureDrawableResource( Window.FEATURE_LEFT_ICON,
|
||||
R.drawable.icon48x48 );
|
||||
|
||||
DwnldDelegate dlgt =
|
||||
new DwnldDelegate( this, savedInstanceState );
|
||||
|
||||
|
|
|
@ -31,6 +31,10 @@ import android.graphics.drawable.Drawable;
|
|||
import android.os.Handler;
|
||||
import android.view.View;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import junit.framework.Assert;
|
||||
|
||||
public class ExpiringDelegate {
|
||||
|
@ -48,7 +52,6 @@ public class ExpiringDelegate {
|
|||
private int m_backPct = -1;
|
||||
private Drawable m_back = null;
|
||||
private boolean m_doFrame = false;
|
||||
private Handler m_handler;
|
||||
private boolean m_haveTurnLocal = false;
|
||||
private long m_startSecs;
|
||||
private Runnable m_runnable = null;
|
||||
|
@ -59,12 +62,79 @@ public class ExpiringDelegate {
|
|||
private static float[] s_points;
|
||||
private DrawSelDelegate m_dsdel;
|
||||
|
||||
// Combine all the timers into one. Since WeakReferences to the same
|
||||
// object aren't equal we need a separate set of their hash codes to
|
||||
// prevent storing duplicates.
|
||||
private static class ExpUpdater implements Runnable {
|
||||
private Handler m_handler;
|
||||
private ArrayList<WeakReference<ExpiringDelegate>> m_refs
|
||||
= new ArrayList<WeakReference<ExpiringDelegate>>();
|
||||
private Set<Integer> m_hashes = new HashSet<Integer>();
|
||||
|
||||
public void run() {
|
||||
int sizeBefore;
|
||||
ArrayList<ExpiringDelegate> dlgts = new ArrayList<ExpiringDelegate>();
|
||||
synchronized( this ) {
|
||||
sizeBefore = m_refs.size();
|
||||
m_hashes.clear();
|
||||
Iterator<WeakReference<ExpiringDelegate>> iter = m_refs.iterator();
|
||||
while ( iter.hasNext() ) {
|
||||
WeakReference<ExpiringDelegate> ref = iter.next();
|
||||
ExpiringDelegate dlgt = ref.get();
|
||||
if ( null == dlgt/* || dlgts.contains( dlgt )*/ ) {
|
||||
iter.remove();
|
||||
} else {
|
||||
dlgts.add(dlgt);
|
||||
m_hashes.add( dlgt.hashCode() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DbgUtils.logdf( "ExpUpdater: ref had %d refs, now has %d expiringdelegate views",
|
||||
sizeBefore, dlgts.size() );
|
||||
|
||||
for ( ExpiringDelegate dlgt : dlgts ) {
|
||||
dlgt.timerFired();
|
||||
}
|
||||
|
||||
reschedule();
|
||||
}
|
||||
|
||||
private void reschedule()
|
||||
{
|
||||
m_handler.postDelayed( this, INTERVAL_SECS * 1000 / 100 );
|
||||
}
|
||||
|
||||
private void add( ExpiringDelegate self )
|
||||
{
|
||||
int hash = self.hashCode();
|
||||
synchronized( this ) {
|
||||
if ( ! m_hashes.contains( hash ) ) {
|
||||
m_hashes.add( hash );
|
||||
m_refs.add( new WeakReference<ExpiringDelegate>(self) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setHandler( Handler handler )
|
||||
{
|
||||
if ( handler != m_handler ) {
|
||||
DbgUtils.logdf( "handler changing from %H to %H",
|
||||
m_handler, handler );
|
||||
m_handler = handler;
|
||||
reschedule();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static ExpUpdater s_updater;
|
||||
static {
|
||||
s_rect = new Rect();
|
||||
s_paint = new Paint();
|
||||
s_paint.setStyle(Paint.Style.STROKE);
|
||||
s_paint.setStrokeWidth( 1 );
|
||||
s_points = new float[4*6];
|
||||
s_updater = new ExpUpdater();
|
||||
}
|
||||
|
||||
public ExpiringDelegate( Context context, View view )
|
||||
|
@ -76,7 +146,7 @@ public class ExpiringDelegate {
|
|||
|
||||
public void setHandler( Handler handler )
|
||||
{
|
||||
m_handler = handler;
|
||||
s_updater.setHandler( handler );
|
||||
}
|
||||
|
||||
public void configure( boolean haveTurn, boolean haveTurnLocal,
|
||||
|
@ -204,54 +274,22 @@ public class ExpiringDelegate {
|
|||
m_pct = 100;
|
||||
} else if ( m_pct < 0 ) {
|
||||
m_pct = 0;
|
||||
} else if ( null != m_handler ) {
|
||||
long onePct = INTERVAL_SECS / 100;
|
||||
long lastStart = m_startSecs + (onePct * m_pct);
|
||||
Assert.assertTrue( lastStart <= now );
|
||||
long nextStartIn = lastStart + onePct - now;
|
||||
// DbgUtils.logf( "pct change %d seconds from now", nextStartIn );
|
||||
|
||||
m_handler.postDelayed( mkRunnable(), 1000 * nextStartIn );
|
||||
} else {
|
||||
s_updater.add( this );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Runnable mkRunnable()
|
||||
private void timerFired()
|
||||
{
|
||||
if ( null == m_runnable ) {
|
||||
m_runnable = mkRunnable( this );
|
||||
if ( m_active ) {
|
||||
figurePct();
|
||||
if ( m_haveTurnLocal ) {
|
||||
m_back = null;
|
||||
setBackground();
|
||||
}
|
||||
m_view.invalidate();
|
||||
}
|
||||
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 ( 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", dlgt.m_view );
|
||||
}
|
||||
dlgt.m_view.invalidate();
|
||||
}
|
||||
} else {
|
||||
DbgUtils.logf( "ExpiringDelegate.run(): reference gc'd" );
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,309 @@
|
|||
/* -*- compile-command: "find-and-ant.sh debug install"; -*- */
|
||||
/*
|
||||
* Copyright 2014-2016 by Eric House (xwords@eehouse.org). All rights
|
||||
* reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package org.eehouse.android.xw4;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.app.Dialog;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentManager.BackStackEntry;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout.LayoutParams;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
public class FragActivity extends FragmentActivity
|
||||
implements FragmentManager.OnBackStackChangedListener {
|
||||
|
||||
private static final int MAX_PANES_LANDSCAPE = 3;
|
||||
|
||||
public interface OrientChangeListener {
|
||||
void orientationChanged();
|
||||
}
|
||||
|
||||
private static FragActivity s_this;
|
||||
|
||||
private LinearLayout m_root;
|
||||
private int m_nextID = 0x00FFFFFF;
|
||||
private int m_maxPanes;
|
||||
private Boolean m_isPortrait;
|
||||
|
||||
@Override
|
||||
public void onCreate( Bundle savedInstanceState )
|
||||
{
|
||||
s_this = this;
|
||||
super.onCreate( savedInstanceState );
|
||||
setContentView( R.layout.fragact );
|
||||
|
||||
m_root = (LinearLayout)findViewById( R.id.main_container );
|
||||
getSupportFragmentManager().addOnBackStackChangedListener( this );
|
||||
|
||||
m_maxPanes = maxPanes();
|
||||
|
||||
// Nothing to do if we're restarting
|
||||
if ( savedInstanceState == null ) {
|
||||
// In case this activity was started with special instructions from an Intent,
|
||||
// pass the Intent's extras to the fragment as arguments
|
||||
addFragmentImpl( new GamesListFrag(), getIntent().getExtras(), null );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed()
|
||||
{
|
||||
DbgUtils.logf( "FragActivity.onBackPressed()" );
|
||||
super.onBackPressed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged( Configuration newConfig )
|
||||
{
|
||||
Rect rect = new Rect();
|
||||
m_root.getWindowVisibleDisplayFrame( rect );
|
||||
|
||||
boolean isPortrait
|
||||
= Configuration.ORIENTATION_PORTRAIT == newConfig.orientation;
|
||||
DbgUtils.logf( "FragActivity.onConfigurationChanged(isPortrait=%b)",
|
||||
isPortrait );
|
||||
m_isPortrait = isPortrait;
|
||||
if ( isPortrait != (rect.width() <= rect.height()) ) {
|
||||
DbgUtils.logdf( "FragActivity.onConfigurationChanged(): isPortrait:"
|
||||
+ " %b; width: %d; height: %d",
|
||||
isPortrait, rect.width(), rect.height() );
|
||||
}
|
||||
int maxPanes = isPortrait? 1 : MAX_PANES_LANDSCAPE;
|
||||
if ( m_maxPanes != maxPanes ) {
|
||||
m_maxPanes = maxPanes;
|
||||
setVisiblePanes();
|
||||
}
|
||||
tellOrientationChanged();
|
||||
super.onConfigurationChanged( newConfig );
|
||||
}
|
||||
|
||||
protected void getFragmentDims( int[] dims )
|
||||
{
|
||||
Rect rect = new Rect();
|
||||
m_root.getWindowVisibleDisplayFrame( rect );
|
||||
int width = rect.width();
|
||||
int height = rect.height();
|
||||
if ( null != m_isPortrait && m_isPortrait && height < width ) {
|
||||
int tmp = width;
|
||||
width = height;
|
||||
height = tmp;
|
||||
}
|
||||
dims[0] = width / Math.min( m_maxPanes, m_root.getChildCount() );
|
||||
dims[1] = height;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dialog onCreateDialog( int id )
|
||||
{
|
||||
return DlgDelegate.onCreateDialog( id );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPrepareDialog( int id, Dialog dialog )
|
||||
{
|
||||
DlgDelegate.onPrepareDialog( id, dialog );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// FragmentManager.OnBackStackChangedListener
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
public void onBackStackChanged()
|
||||
{
|
||||
DbgUtils.logf( "FragActivity.onBackStackChanged()" );
|
||||
// make sure the right-most are visible
|
||||
int fragCount = getSupportFragmentManager().getBackStackEntryCount();
|
||||
if ( 0 == fragCount ) {
|
||||
finish();
|
||||
} else if ( fragCount == m_root.getChildCount() - 1 ) {
|
||||
m_root.removeViewAt( fragCount );
|
||||
setVisiblePanes();
|
||||
}
|
||||
}
|
||||
|
||||
// public void launchDictFrag( Bundle args )
|
||||
// {
|
||||
// // DictBrowseFrag dbf = new DictBrowseFrag();
|
||||
// // dbf.setArguments( args );
|
||||
// // addFragment( dbf );
|
||||
// }
|
||||
|
||||
protected void finishFragment()
|
||||
{
|
||||
popFragment( null );
|
||||
}
|
||||
|
||||
protected void popFragment( Fragment frag )
|
||||
{
|
||||
getSupportFragmentManager().popBackStack();
|
||||
}
|
||||
|
||||
private void addFragmentImpl( Fragment fragment, Bundle bundle,
|
||||
Delegator parent )
|
||||
{
|
||||
fragment.setArguments( bundle );
|
||||
addFragmentImpl( fragment, parent );
|
||||
}
|
||||
|
||||
private void addFragmentImpl( Fragment fragment, Delegator delegator )
|
||||
{
|
||||
String newName = fragment.getClass().getName();
|
||||
boolean replace = false;
|
||||
FragmentManager fm = getSupportFragmentManager();
|
||||
int fragCount = fm.getBackStackEntryCount();
|
||||
int containerCount = m_root.getChildCount();
|
||||
DbgUtils.logf( "fragCount: %d; containerCount: %d", fragCount, containerCount );
|
||||
// Assert.assertTrue( fragCount == containerCount );
|
||||
|
||||
// Replace IF we're adding something of the same class at right OR if
|
||||
// we're adding something with the existing left pane as its parent
|
||||
// (delegator)
|
||||
if ( 0 < fragCount ) {
|
||||
FragmentManager.BackStackEntry entry = fm.getBackStackEntryAt( fragCount - 1 );
|
||||
String curName = entry.getName();
|
||||
DbgUtils.logf( "name of last entry: %s", curName );
|
||||
replace = curName.equals( newName );
|
||||
|
||||
if ( !replace && 1 < fragCount ) {
|
||||
entry = fm.getBackStackEntryAt( fragCount - 2 );
|
||||
curName = entry.getName();
|
||||
String delName = delegator.getClass().getName();
|
||||
DbgUtils.logf( "comparing %s, %s", curName, delName );
|
||||
replace = curName.equals( delName );
|
||||
}
|
||||
|
||||
if ( replace ) {
|
||||
fm.popBackStack();
|
||||
}
|
||||
}
|
||||
|
||||
// Replace doesn't seem to work with generated IDs, so we'll create a
|
||||
// new FrameLayout each time. If we're replacing, we'll replace the
|
||||
// current rightmost FrameLayout. Otherwise we'll add a new one.
|
||||
FrameLayout cont = new FrameLayout( this );
|
||||
cont.setLayoutParams( new LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f) );
|
||||
int id = --m_nextID;
|
||||
cont.setId( id );
|
||||
m_root.addView( cont, replace ? containerCount - 1 : containerCount );
|
||||
|
||||
if ( !replace && containerCount >= m_maxPanes ) {
|
||||
int indx = containerCount - m_maxPanes;
|
||||
View child = m_root.getChildAt( indx );
|
||||
child.setVisibility( View.GONE );
|
||||
|
||||
setMenuVisibility( child, false );
|
||||
|
||||
DbgUtils.logf( "hiding %dth container", indx );
|
||||
}
|
||||
|
||||
fm.beginTransaction()
|
||||
.add( id, fragment )
|
||||
.addToBackStack( newName )
|
||||
.commit();
|
||||
// fm.executePendingTransactions();
|
||||
}
|
||||
|
||||
private void setVisiblePanes()
|
||||
{
|
||||
// hide all but the right-most m_maxPanes children
|
||||
int nPanes = m_root.getChildCount();
|
||||
for ( int ii = 0; ii < nPanes; ++ii ) {
|
||||
View child = m_root.getChildAt( ii );
|
||||
boolean visible = ii >= nPanes - m_maxPanes;
|
||||
DbgUtils.logf( "pane %d: visible=%b", ii, visible );
|
||||
child.setVisibility( visible ? View.VISIBLE : View.GONE );
|
||||
setMenuVisibility( child, visible );
|
||||
}
|
||||
}
|
||||
|
||||
private void setMenuVisibility( View cont, boolean visible )
|
||||
{
|
||||
FrameLayout layout = (FrameLayout)cont;
|
||||
FragmentManager fm = getSupportFragmentManager();
|
||||
int hidingId = layout.getId();
|
||||
Fragment frag = fm.findFragmentById( hidingId );
|
||||
if ( null != frag ) { // hasn't been popped?
|
||||
frag.setMenuVisibility( visible );
|
||||
}
|
||||
}
|
||||
|
||||
// Walk all Fragment children and if they care notify of change.
|
||||
private void tellOrientationChanged()
|
||||
{
|
||||
FragmentManager fm = getSupportFragmentManager();
|
||||
int nPanes = m_root.getChildCount();
|
||||
for ( int ii = 0; ii < nPanes; ++ii ) {
|
||||
FrameLayout frame = (FrameLayout)m_root.getChildAt( ii );
|
||||
int id = frame.getId();
|
||||
Fragment frag = fm.findFragmentById( id );
|
||||
if ( null == frag ) {
|
||||
DbgUtils.logf( "tellOrienationChanged: NO FRAG at %d, id=%d", ii, id );
|
||||
} else if ( frag instanceof OrientChangeListener ) {
|
||||
((OrientChangeListener)frag).orientationChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int maxPanes()
|
||||
{
|
||||
int result;
|
||||
int orientation = getResources().getConfiguration().orientation;
|
||||
if ( XWPrefs.getIsTablet( this )
|
||||
&& Configuration.ORIENTATION_LANDSCAPE == orientation ) {
|
||||
result = 2;
|
||||
} else {
|
||||
result = 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static FragActivity getThis()
|
||||
{
|
||||
Assert.assertNotNull( s_this );
|
||||
return s_this;
|
||||
}
|
||||
|
||||
public static void addFragment( Fragment fragment, Bundle bundle )
|
||||
{
|
||||
addFragment( fragment, bundle, null );
|
||||
}
|
||||
|
||||
public static void addFragment( Fragment fragment, Bundle bundle,
|
||||
Delegator parent )
|
||||
{
|
||||
getThis().addFragmentImpl( fragment, bundle, parent );
|
||||
}
|
||||
|
||||
public static void addFragmentForResult( Fragment fragment, Bundle bundle,
|
||||
RequestCode requestCode, Delegator parent )
|
||||
{
|
||||
getThis().addFragmentImpl( fragment, bundle, parent );
|
||||
}
|
||||
}
|
|
@ -37,13 +37,13 @@ public class GCMIntentService extends GCMBaseIntentService {
|
|||
@Override
|
||||
protected void onError( Context context, String error )
|
||||
{
|
||||
DbgUtils.logf("GCMIntentService.onError(%s)", error );
|
||||
DbgUtils.logdf("GCMIntentService.onError(%s)", error );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRegistered( Context context, String regId )
|
||||
{
|
||||
DbgUtils.logf( "GCMIntentService.onRegistered(%s)", regId );
|
||||
DbgUtils.logdf( "GCMIntentService.onRegistered(%s)", regId );
|
||||
DevID.setGCMDevID( context, regId );
|
||||
notifyRelayService( context, true );
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ public class GCMIntentService extends GCMBaseIntentService {
|
|||
@Override
|
||||
protected void onUnregistered( Context context, String regId )
|
||||
{
|
||||
DbgUtils.logf( "GCMIntentService.onUnregistered(%s)", regId );
|
||||
DbgUtils.logdf( "GCMIntentService.onUnregistered(%s)", regId );
|
||||
DevID.clearGCMDevID( context );
|
||||
RelayService.devIDChanged();
|
||||
notifyRelayService( context, false );
|
||||
|
@ -60,13 +60,13 @@ public class GCMIntentService extends GCMBaseIntentService {
|
|||
@Override
|
||||
protected void onMessage( Context context, Intent intent )
|
||||
{
|
||||
DbgUtils.logf( "GCMIntentService.onMessage()" );
|
||||
DbgUtils.logdf( "GCMIntentService.onMessage()" );
|
||||
notifyRelayService( context, true );
|
||||
|
||||
String value;
|
||||
boolean ignoreIt = XWApp.GCM_IGNORED;
|
||||
if ( ignoreIt ) {
|
||||
DbgUtils.logf( "received GCM but ignoring it" );
|
||||
DbgUtils.logdf( "received GCM but ignoring it" );
|
||||
} else {
|
||||
value = intent.getStringExtra( "checkUpdates" );
|
||||
if ( null != value && Boolean.parseBoolean( value ) ) {
|
||||
|
@ -123,7 +123,7 @@ public class GCMIntentService extends GCMBaseIntentService {
|
|||
GCMRegistrar.checkDevice( app );
|
||||
// GCMRegistrar.checkManifest( app );
|
||||
String regId = DevID.getGCMDevID( app );
|
||||
if (regId.equals("")) {
|
||||
if ( regId.equals("") ) {
|
||||
GCMRegistrar.register( app, GCMConsts.SENDER_ID );
|
||||
}
|
||||
} catch ( UnsupportedOperationException uoe ) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* -*- compile-command: "find-and-ant.sh debug install"; -*- */
|
||||
/*
|
||||
* Copyright 2009 - 2015 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
|
||||
|
@ -83,7 +83,6 @@ public class GameConfigDelegate extends DelegateBase
|
|||
private Button m_playButton;
|
||||
private ImageButton m_refreshRoomsButton;
|
||||
private View m_connectSetRelay;
|
||||
private View m_connectSetSMS;
|
||||
private Spinner m_dictSpinner;
|
||||
private Spinner m_playerDictSpinner;
|
||||
private Spinner m_roomChoose;
|
||||
|
@ -463,9 +462,10 @@ public class GameConfigDelegate extends DelegateBase
|
|||
|
||||
m_cp = CommonPrefs.get( m_activity );
|
||||
|
||||
Intent intent = getIntent();
|
||||
m_rowid = intent.getLongExtra( GameUtils.INTENT_KEY_ROWID, -1 );
|
||||
m_forResult = intent.getBooleanExtra( INTENT_FORRESULT_ROWID, false );
|
||||
Bundle args = getArguments();
|
||||
m_rowid = args.getLong( GameUtils.INTENT_KEY_ROWID, DBUtils.ROWID_NOTFOUND );
|
||||
Assert.assertTrue( DBUtils.ROWID_NOTFOUND != m_rowid );
|
||||
m_forResult = args.getBoolean( INTENT_FORRESULT_ROWID, false );
|
||||
|
||||
m_connectSetRelay = findViewById( R.id.connect_set_relay );
|
||||
|
||||
|
@ -1167,7 +1167,7 @@ public class GameConfigDelegate extends DelegateBase
|
|||
&& 0 == m_car.ip_relay_invite.length() ) {
|
||||
showOKOnlyDialog( R.string.no_empty_rooms );
|
||||
} else {
|
||||
GameUtils.launchGameAndFinish( m_activity, m_rowid );
|
||||
GameUtils.launchGameAndFinish( getDelegator(), m_rowid );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1196,14 +1196,24 @@ public class GameConfigDelegate extends DelegateBase
|
|||
return DeviceRole.SERVER_STANDALONE == m_giOrig.serverRole;
|
||||
}
|
||||
|
||||
public static void editForResult( Activity parent, RequestCode requestCode,
|
||||
public static void editForResult( Delegator delegator,
|
||||
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.ordinal() );
|
||||
Activity activity = delegator.getActivity();
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putLong( GameUtils.INTENT_KEY_ROWID, rowID );
|
||||
bundle.putBoolean( INTENT_FORRESULT_ROWID, true );
|
||||
|
||||
if ( activity instanceof FragActivity ) {
|
||||
FragActivity.addFragmentForResult( new GameConfigFrag(), bundle,
|
||||
requestCode, delegator );
|
||||
} else {
|
||||
Intent intent = new Intent( activity, GameConfigActivity.class );
|
||||
intent.setAction( Intent.ACTION_EDIT );
|
||||
intent.putExtras( bundle );
|
||||
activity.startActivityForResult( intent, requestCode.ordinal() );
|
||||
}
|
||||
}
|
||||
|
||||
private void setConnLabel()
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/* -*- compile-command: "find-and-ant.sh debug install"; -*- */
|
||||
/*
|
||||
* Copyright 2016 by Eric House (xwords@eehouse.org). All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package org.eehouse.android.xw4;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
public class GameConfigFrag extends XWFragment {
|
||||
|
||||
@Override
|
||||
public void onCreate( Bundle sis )
|
||||
{
|
||||
super.onCreate( new GameConfigDelegate( this, sis ), sis, true );
|
||||
}
|
||||
}
|
|
@ -43,13 +43,16 @@ import java.util.concurrent.LinkedBlockingQueue;
|
|||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.eehouse.android.xw4.jni.GameSummary;
|
||||
import org.eehouse.android.xw4.loc.LocUtils;
|
||||
import org.eehouse.android.xw4.jni.CurGameInfo.DeviceRole;
|
||||
import org.eehouse.android.xw4.jni.GameSummary;
|
||||
import org.eehouse.android.xw4.jni.JNIThread;
|
||||
import org.eehouse.android.xw4.loc.LocUtils;
|
||||
|
||||
public class GameListItem extends LinearLayout
|
||||
implements View.OnClickListener, SelectableItem.LongClickHandler {
|
||||
|
||||
private static final int SUMMARY_WAIT_MSECS = 1000;
|
||||
|
||||
private static HashSet<Long> s_invalRows = new HashSet<Long>();
|
||||
|
||||
private Activity m_activity;
|
||||
|
@ -59,7 +62,7 @@ public class GameListItem extends LinearLayout
|
|||
private View m_hideable;
|
||||
private ImageView m_thumb;
|
||||
private ExpiringTextView m_name;
|
||||
private View m_viewUnloaded;
|
||||
private TextView m_viewUnloaded;
|
||||
private View m_viewLoaded;
|
||||
private LinearLayout m_list;
|
||||
private TextView m_state;
|
||||
|
@ -129,13 +132,7 @@ public class GameListItem extends LinearLayout
|
|||
// as we're back on the UI thread.
|
||||
++m_loadingCount;
|
||||
|
||||
LoadItemTask task = new LoadItemTask();
|
||||
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 {
|
||||
task.execute();
|
||||
}
|
||||
new LoadItemTask().execute();
|
||||
}
|
||||
|
||||
public void invalName()
|
||||
|
@ -195,7 +192,7 @@ public class GameListItem extends LinearLayout
|
|||
m_name = (ExpiringTextView)findViewById( R.id.game_name );
|
||||
m_expandButton = (ImageButton)findViewById( R.id.expander );
|
||||
m_expandButton.setOnClickListener( this );
|
||||
m_viewUnloaded = findViewById( R.id.view_unloaded );
|
||||
m_viewUnloaded = (TextView)findViewById( R.id.view_unloaded );
|
||||
m_viewLoaded = findViewById( R.id.view_loaded );
|
||||
m_list = (LinearLayout)findViewById( R.id.player_list );
|
||||
m_state = (TextView)findViewById( R.id.state );
|
||||
|
@ -357,13 +354,23 @@ public class GameListItem extends LinearLayout
|
|||
@Override
|
||||
protected GameSummary doInBackground( Void... unused )
|
||||
{
|
||||
return DBUtils.getSummary( m_context, m_rowid, 150 );
|
||||
return DBUtils.getSummary( m_context, m_rowid, SUMMARY_WAIT_MSECS );
|
||||
} // doInBackground
|
||||
|
||||
@Override
|
||||
protected void onPostExecute( GameSummary summary )
|
||||
{
|
||||
if ( 0 == --m_loadingCount ) {
|
||||
if ( null == summary ) {
|
||||
// Try again. Maybe it's open
|
||||
JNIThread thread = JNIThread.getRetained( m_rowid );
|
||||
if ( null != thread ) {
|
||||
summary = DBUtils.getSummary( m_context,
|
||||
thread.getLock() );
|
||||
thread.release();
|
||||
}
|
||||
}
|
||||
|
||||
m_summary = summary;
|
||||
boolean expanded = DBUtils.getExpanded( m_context, m_rowid );
|
||||
|
||||
|
@ -371,6 +378,11 @@ public class GameListItem extends LinearLayout
|
|||
|
||||
setData( summary, expanded );
|
||||
setLoaded( null != m_summary );
|
||||
if ( null == summary ) {
|
||||
m_viewUnloaded
|
||||
.setText( LocUtils.getString( m_context,
|
||||
R.string.summary_busy ) );
|
||||
}
|
||||
synchronized( s_invalRows ) {
|
||||
s_invalRows.remove( m_rowid );
|
||||
}
|
||||
|
|
|
@ -28,12 +28,22 @@ import junit.framework.Assert;
|
|||
// obtainable when other read locks are granted but not when a
|
||||
// write lock is. Write-locks are exclusive.
|
||||
public class GameLock {
|
||||
private static final int SLEEP_TIME = 25;
|
||||
private static final boolean DEBUG_LOCKS = false;
|
||||
private static final boolean THROW_ON_LOCKED = true;
|
||||
private static final int SLEEP_TIME = 100;
|
||||
private static final long ASSERT_TIME = 2000;
|
||||
private static final long THROW_TIME = 1000;
|
||||
private long m_rowid;
|
||||
private boolean m_isForWrite;
|
||||
private int m_lockCount;
|
||||
private StackTraceElement[] m_lockTrace;
|
||||
|
||||
static {
|
||||
Assert.assertTrue( THROW_TIME <= ASSERT_TIME );
|
||||
}
|
||||
|
||||
public static class GameLockedException extends RuntimeException {}
|
||||
|
||||
private static HashMap<Long, GameLock>
|
||||
s_locks = new HashMap<Long,GameLock>();
|
||||
|
||||
|
@ -43,7 +53,7 @@ public class GameLock {
|
|||
m_rowid = rowid;
|
||||
m_isForWrite = isForWrite;
|
||||
m_lockCount = 0;
|
||||
if ( XWApp.DEBUG_LOCKS ) {
|
||||
if ( DEBUG_LOCKS ) {
|
||||
DbgUtils.logf( "GameLock.GameLock(rowid:%d,isForWrite:%b)=>"
|
||||
+ "this: %H", rowid, isForWrite, this );
|
||||
DbgUtils.printStack();
|
||||
|
@ -69,26 +79,26 @@ public class GameLock {
|
|||
++m_lockCount;
|
||||
gotIt = true;
|
||||
|
||||
if ( XWApp.DEBUG_LOCKS ) {
|
||||
if ( DEBUG_LOCKS ) {
|
||||
StackTraceElement[] trace
|
||||
= Thread.currentThread().getStackTrace();
|
||||
m_lockTrace = new StackTraceElement[trace.length];
|
||||
System.arraycopy( trace, 0, m_lockTrace, 0, trace.length );
|
||||
}
|
||||
} else if ( this == owner && ! m_isForWrite ) {
|
||||
if ( XWApp.DEBUG_LOCKS ) {
|
||||
if ( DEBUG_LOCKS ) {
|
||||
DbgUtils.logf( "tryLock(): incrementing lock count" );
|
||||
}
|
||||
Assert.assertTrue( 0 == m_lockCount );
|
||||
++m_lockCount;
|
||||
gotIt = true;
|
||||
owner = null;
|
||||
} else if ( XWApp.DEBUG_LOCKS ) {
|
||||
} else if ( DEBUG_LOCKS ) {
|
||||
DbgUtils.logf( "tryLock(): rowid %d already held by lock %H",
|
||||
m_rowid, owner );
|
||||
}
|
||||
}
|
||||
if ( XWApp.DEBUG_LOCKS ) {
|
||||
if ( DEBUG_LOCKS ) {
|
||||
DbgUtils.logf( "GameLock.tryLock %H (rowid=%d) => %b",
|
||||
this, m_rowid, gotIt );
|
||||
}
|
||||
|
@ -105,11 +115,11 @@ public class GameLock {
|
|||
public GameLock lock( long maxMillis )
|
||||
{
|
||||
GameLock result = null;
|
||||
final long assertTime = 2000;
|
||||
Assert.assertTrue( maxMillis < assertTime );
|
||||
Assert.assertTrue( maxMillis <= ASSERT_TIME );
|
||||
Assert.assertTrue( maxMillis <= THROW_TIME );
|
||||
long sleptTime = 0;
|
||||
|
||||
if ( XWApp.DEBUG_LOCKS ) {
|
||||
if ( DEBUG_LOCKS ) {
|
||||
DbgUtils.logf( "lock %H (rowid:%d, maxMillis=%d)", this, m_rowid,
|
||||
maxMillis );
|
||||
}
|
||||
|
@ -120,9 +130,9 @@ public class GameLock {
|
|||
result = this;
|
||||
break;
|
||||
}
|
||||
if ( XWApp.DEBUG_LOCKS ) {
|
||||
if ( DEBUG_LOCKS ) {
|
||||
DbgUtils.logf( "GameLock.lock() %H failed; sleeping", this );
|
||||
if ( 0 == sleptTime || sleptTime + SLEEP_TIME >= assertTime ) {
|
||||
if ( 0 == sleptTime || sleptTime + SLEEP_TIME >= ASSERT_TIME ) {
|
||||
DbgUtils.logf( "lock %H seeking stack:", curOwner );
|
||||
DbgUtils.printStack( curOwner.m_lockTrace );
|
||||
DbgUtils.logf( "lock %H seeking stack:", this );
|
||||
|
@ -137,18 +147,20 @@ public class GameLock {
|
|||
break;
|
||||
}
|
||||
|
||||
if ( XWApp.DEBUG_LOCKS ) {
|
||||
if ( DEBUG_LOCKS ) {
|
||||
DbgUtils.logf( "GameLock.lock() %H awake; "
|
||||
+ "sleptTime now %d millis", this, sleptTime );
|
||||
}
|
||||
|
||||
if ( 0 < maxMillis && sleptTime >= maxMillis ) {
|
||||
break;
|
||||
} else if ( sleptTime >= assertTime ) {
|
||||
if ( XWApp.DEBUG_LOCKS ) {
|
||||
} else if ( THROW_ON_LOCKED && sleptTime >= THROW_TIME ) {
|
||||
throw new GameLockedException();
|
||||
} else if ( sleptTime >= ASSERT_TIME ) {
|
||||
if ( DEBUG_LOCKS ) {
|
||||
DbgUtils.logf( "lock %H overlocked", this );
|
||||
}
|
||||
Assert.fail();
|
||||
Assert.fail(); // firing
|
||||
}
|
||||
}
|
||||
// DbgUtils.logf( "GameLock.lock(%s) done", m_path );
|
||||
|
@ -167,7 +179,7 @@ public class GameLock {
|
|||
}
|
||||
--m_lockCount;
|
||||
|
||||
if ( XWApp.DEBUG_LOCKS ) {
|
||||
if ( DEBUG_LOCKS ) {
|
||||
DbgUtils.logf( "GameLock.unlock: this: %H (rowid:%d) unlocked",
|
||||
this, m_rowid );
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import android.graphics.Bitmap;
|
|||
import android.graphics.Rect;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
|
||||
import android.text.Html;
|
||||
import android.text.TextUtils;
|
||||
|
@ -219,6 +220,13 @@ public class GameUtils {
|
|||
return rowid;
|
||||
}
|
||||
|
||||
public static void deleteGame( Context context, GameLock lock, boolean informNow )
|
||||
{
|
||||
tellDied( context, lock, informNow );
|
||||
Utils.cancelNotification( context, (int)lock.getRowid() );
|
||||
DBUtils.deleteGame( context, lock );
|
||||
}
|
||||
|
||||
public static boolean deleteGame( Context context, long rowid,
|
||||
boolean informNow )
|
||||
{
|
||||
|
@ -226,9 +234,7 @@ public class GameUtils {
|
|||
// does this need to be synchronized?
|
||||
GameLock lock = new GameLock( rowid, true );
|
||||
if ( lock.tryLock() ) {
|
||||
tellDied( context, lock, informNow );
|
||||
Utils.cancelNotification( context, (int)rowid );
|
||||
DBUtils.deleteGame( context, lock );
|
||||
deleteGame( context, lock, informNow );
|
||||
lock.unlock();
|
||||
success = true;
|
||||
} else {
|
||||
|
@ -368,6 +374,7 @@ public class GameUtils {
|
|||
ThumbCanvas canvas = new ThumbCanvas( context, thumb );
|
||||
XwJNI.board_setDraw( gamePtr, canvas );
|
||||
XwJNI.board_invalAll( gamePtr );
|
||||
Assert.assertNotNull( gamePtr );
|
||||
XwJNI.board_draw( gamePtr );
|
||||
}
|
||||
}
|
||||
|
@ -745,6 +752,15 @@ public class GameUtils {
|
|||
// }
|
||||
// }
|
||||
|
||||
|
||||
public static String[] dictNames( Context context, GameLock lock )
|
||||
{
|
||||
byte[] stream = savedGame( context, lock );
|
||||
CurGameInfo gi = new CurGameInfo( context );
|
||||
XwJNI.gi_from_stream( gi, stream );
|
||||
return gi.dictNames();
|
||||
}
|
||||
|
||||
public static String[] dictNames( Context context, long rowid,
|
||||
int[] missingLang )
|
||||
{
|
||||
|
@ -822,26 +838,39 @@ public class GameUtils {
|
|||
return file.endsWith( XWConstants.GAME_EXTN );
|
||||
}
|
||||
|
||||
public static void launchGame( Activity activity, long rowid,
|
||||
public static Bundle makeLaunchExtras( long rowid, boolean invited )
|
||||
{
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putLong( INTENT_KEY_ROWID, rowid );
|
||||
if ( invited ) {
|
||||
bundle.putBoolean( INVITED, true );
|
||||
}
|
||||
return bundle;
|
||||
}
|
||||
|
||||
public static void launchGame( Delegator delegator, long rowid,
|
||||
boolean invited )
|
||||
{
|
||||
Intent intent = new Intent( activity, BoardActivity.class );
|
||||
intent.putExtra( INTENT_KEY_ROWID, rowid );
|
||||
if ( invited ) {
|
||||
intent.putExtra( INVITED, true );
|
||||
Activity activity = delegator.getActivity();
|
||||
Bundle extras = makeLaunchExtras( rowid, invited );
|
||||
if ( activity instanceof FragActivity ) {
|
||||
FragActivity.addFragment( new BoardFrag(), extras, delegator );
|
||||
} else {
|
||||
Intent intent = new Intent( activity, BoardActivity.class );
|
||||
intent.putExtras( extras );
|
||||
activity.startActivity( intent );
|
||||
}
|
||||
activity.startActivity( intent );
|
||||
}
|
||||
|
||||
public static void launchGame( Activity activity, long rowid )
|
||||
public static void launchGame( Delegator delegator, long rowid )
|
||||
{
|
||||
launchGame( activity, rowid, false );
|
||||
launchGame( delegator, rowid, false );
|
||||
}
|
||||
|
||||
public static void launchGameAndFinish( Activity activity, long rowid )
|
||||
public static void launchGameAndFinish( Delegator delegator, long rowid )
|
||||
{
|
||||
launchGame( activity, rowid );
|
||||
activity.finish();
|
||||
launchGame( delegator, rowid );
|
||||
delegator.getActivity().finish();
|
||||
}
|
||||
|
||||
private static class FeedUtilsImpl extends UtilCtxtImpl {
|
||||
|
@ -862,9 +891,9 @@ public class GameUtils {
|
|||
m_gameOver = false;
|
||||
}
|
||||
@Override
|
||||
public void showChat( String msg, String fromName )
|
||||
public void showChat( String msg, int fromIndx, String fromName )
|
||||
{
|
||||
DBUtils.appendChatHistory( m_context, m_rowid, msg, false );
|
||||
DBUtils.appendChatHistory( m_context, m_rowid, msg, fromIndx );
|
||||
m_gotChat = true;
|
||||
m_chatFrom = fromName;
|
||||
m_chat = msg;
|
||||
|
@ -1036,11 +1065,10 @@ public class GameUtils {
|
|||
}
|
||||
|
||||
if ( forceNew || !madeGame ) {
|
||||
XwJNI.game_makeNewGame( gamePtr, gi, util,
|
||||
JNIUtilsImpl.get(context),
|
||||
(DrawCtx)null,
|
||||
cp, sink, dictNames, pairs.m_bytes,
|
||||
pairs.m_paths, langName );
|
||||
XwJNI.game_makeNewGame( gamePtr, gi, dictNames, pairs.m_bytes,
|
||||
pairs.m_paths, langName, util,
|
||||
JNIUtilsImpl.get(context), (DrawCtx)null,
|
||||
cp, sink );
|
||||
}
|
||||
|
||||
if ( null != car ) {
|
||||
|
@ -1059,12 +1087,20 @@ public class GameUtils {
|
|||
DBUtils.saveSummary( context, lock, summary );
|
||||
} // applyChanges
|
||||
|
||||
public static void doConfig( Activity activity, long rowid, Class clazz )
|
||||
public static void doConfig( Delegator delegator, long rowid )
|
||||
{
|
||||
Intent intent = new Intent( activity, clazz );
|
||||
intent.setAction( Intent.ACTION_EDIT );
|
||||
intent.putExtra( INTENT_KEY_ROWID, rowid );
|
||||
activity.startActivity( intent );
|
||||
Bundle extras = new Bundle();
|
||||
extras.putLong( INTENT_KEY_ROWID, rowid );
|
||||
|
||||
Activity activity = delegator.getActivity();
|
||||
if ( activity instanceof FragActivity ) {
|
||||
FragActivity.addFragment( new GameConfigFrag(), extras, delegator );
|
||||
} else {
|
||||
Intent intent = new Intent( activity, GameConfigActivity.class );
|
||||
intent.setAction( Intent.ACTION_EDIT );
|
||||
intent.putExtras( extras );
|
||||
activity.startActivity( intent );
|
||||
}
|
||||
}
|
||||
|
||||
public static String formatGameID( int gameID )
|
||||
|
@ -1090,6 +1126,14 @@ public class GameUtils {
|
|||
return rint;
|
||||
}
|
||||
|
||||
// public static void postSelfNotification( Context context, long rowid )
|
||||
// {
|
||||
// Assert.assertTrue( BuildConfig.DEBUG );
|
||||
// Intent intent = GamesListDelegate.makeRowidIntent( context, rowid );
|
||||
// Utils.postNotification( context, intent, "launch",
|
||||
// String.format("%d", rowid), (int)rowid );
|
||||
// }
|
||||
|
||||
public static void postMoveNotification( Context context, long rowid,
|
||||
BackMoveResult bmr,
|
||||
boolean isTurnNow )
|
||||
|
|
|
@ -54,4 +54,12 @@ public class GamesListActivity extends XWActivity {
|
|||
super.onNewIntent( intent );
|
||||
m_dlgt.onNewIntent( intent );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// GamesListDelegator interface
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
public void launchGame( long rowID, boolean invited )
|
||||
{
|
||||
GameUtils.launchGame( this, rowID, invited );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* -*- compile-command: "find-and-ant.sh debug install"; -*- */
|
||||
/*
|
||||
* Copyright 2009 - 2015 by Eric House (xwords@eehouse.org). All
|
||||
* Copyright 2009 - 2016 by Eric House (xwords@eehouse.org). All
|
||||
* rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -566,7 +566,6 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
|
||||
private Activity m_activity;
|
||||
private static GamesListDelegate s_self;
|
||||
private Delegator m_delegator;
|
||||
private GameListAdapter m_adapter;
|
||||
private Handler m_handler;
|
||||
private String m_missingDict;
|
||||
|
@ -581,7 +580,7 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
private String m_nameField;
|
||||
private NetLaunchInfo m_netLaunchInfo;
|
||||
private GameNamer m_namer;
|
||||
private Set<Long> m_launchedGames;
|
||||
private Set<Long> m_launchedGames; // prevent problems with double-taps
|
||||
private boolean m_menuPrepared;
|
||||
private boolean m_moveAfterNewGroup;
|
||||
private Set<Long> m_selGames;
|
||||
|
@ -596,7 +595,6 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
public GamesListDelegate( Delegator delegator, Bundle sis )
|
||||
{
|
||||
super( delegator, sis, R.layout.game_list, R.menu.games_list_menu );
|
||||
m_delegator = delegator;
|
||||
m_activity = delegator.getActivity();
|
||||
m_launchedGames = new HashSet<Long>();
|
||||
s_self = this;
|
||||
|
@ -920,6 +918,9 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
@Override
|
||||
protected void init( Bundle savedInstanceState )
|
||||
{
|
||||
m_origTitle = getTitle();
|
||||
Assert.assertTrue( m_origTitle.equals( getString(R.string.app_name) ) );
|
||||
|
||||
m_handler = new Handler();
|
||||
// Next line useful if contents of DB are crashing app on start
|
||||
// DBUtils.saveDB( m_activity );
|
||||
|
@ -946,18 +947,22 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
};
|
||||
|
||||
mkListAdapter();
|
||||
ListView listView = getListView();
|
||||
listView.setOnItemLongClickListener( this );
|
||||
getListView().setOnItemLongClickListener( this );
|
||||
|
||||
NetUtils.informOfDeaths( m_activity );
|
||||
|
||||
tryStartsFromIntent( getIntent() );
|
||||
|
||||
getDictForLangIf();
|
||||
|
||||
m_origTitle = getTitle();
|
||||
} // init
|
||||
|
||||
// protected View onCreateView( Bundle savedInstanceState )
|
||||
// {
|
||||
// View result = inflate( R.layout.game_list );
|
||||
// // init( savedInstanceState );
|
||||
// return result;
|
||||
// }
|
||||
|
||||
// called when we're brought to the front (probably as a result of
|
||||
// notification)
|
||||
protected void onNewIntent( Intent intent )
|
||||
|
@ -984,7 +989,9 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
protected void onDestroy()
|
||||
{
|
||||
DBUtils.clearDBChangeListener( this );
|
||||
s_self = null;
|
||||
if ( s_self == this ) {
|
||||
s_self = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void onSaveInstanceState( Bundle outState )
|
||||
|
@ -1040,16 +1047,7 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
if ( hasFocus ) {
|
||||
updateField();
|
||||
|
||||
if ( 0 != m_launchedGames.size() ) {
|
||||
long rowid = m_launchedGames.iterator().next();
|
||||
m_launchedGames.remove( rowid );
|
||||
|
||||
if ( m_adapter.inExpandedGroup( rowid ) ) {
|
||||
setSelGame( rowid );
|
||||
} else {
|
||||
clearSelections();
|
||||
}
|
||||
}
|
||||
m_launchedGames.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1103,11 +1101,13 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
public void itemClicked( SelectableItem.LongClickHandler clicked,
|
||||
GameSummary summary )
|
||||
{
|
||||
DbgUtils.logf( "GamesListDelegate.itemClicked()" );
|
||||
// We need a way to let the user get back to the basic-config
|
||||
// dialog in case it was dismissed. That way it to check for
|
||||
// an empty room name.
|
||||
if ( clicked instanceof GameListItem ) {
|
||||
long rowid = ((GameListItem)clicked).getRowID();
|
||||
DbgUtils.logf( "GamesListDelegate.itemClicked(%d)", rowid );
|
||||
if ( ! m_launchedGames.contains( rowid ) ) {
|
||||
showNotAgainDlgThen( R.string.not_again_newselect,
|
||||
R.string.key_notagain_newselect,
|
||||
|
@ -1297,7 +1297,7 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
if ( !cancelled ) {
|
||||
long rowID = data.getLongExtra( GameUtils.INTENT_KEY_ROWID,
|
||||
DBUtils.ROWID_NOTFOUND );
|
||||
GameUtils.launchGame( m_activity, rowID );
|
||||
GameUtils.launchGame( getDelegator(), rowID );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1325,7 +1325,7 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
@Override
|
||||
public boolean onPrepareOptionsMenu( Menu menu )
|
||||
{
|
||||
int nGamesSelected = m_selGames.size();
|
||||
int nGamesSelected = m_selGames.size(); // NPE!
|
||||
int nGroupsSelected = m_selGroupIDs.size();
|
||||
int groupCount = m_adapter.getGroupCount();
|
||||
m_menuPrepared = 0 == nGamesSelected || 0 == nGroupsSelected;
|
||||
|
@ -1482,7 +1482,7 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
break;
|
||||
|
||||
case R.id.games_menu_study:
|
||||
StudyListDelegate.launchOrAlert( m_activity, StudyListDelegate.NO_LANG, this );
|
||||
StudyListDelegate.launchOrAlert( getDelegator(), StudyListDelegate.NO_LANG, this );
|
||||
break;
|
||||
|
||||
case R.id.games_menu_about:
|
||||
|
@ -1677,7 +1677,7 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
break;
|
||||
|
||||
case R.id.games_game_config:
|
||||
GameUtils.doConfig( m_activity, selRowIDs[0], GameConfigActivity.class );
|
||||
GameUtils.doConfig( getDelegator(), selRowIDs[0] );
|
||||
break;
|
||||
|
||||
case R.id.games_game_move:
|
||||
|
@ -1967,7 +1967,13 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
private void startFirstHasDict( long rowid )
|
||||
{
|
||||
if ( -1 != rowid && DBUtils.haveGame( m_activity, rowid ) ) {
|
||||
if ( GameUtils.gameDictsHere( m_activity, rowid ) ) {
|
||||
boolean haveDict;
|
||||
try {
|
||||
haveDict = GameUtils.gameDictsHere( m_activity, rowid );
|
||||
} catch ( GameLock.GameLockedException gle ) {
|
||||
haveDict = true;
|
||||
}
|
||||
if ( haveDict ) {
|
||||
launchGame( rowid );
|
||||
}
|
||||
}
|
||||
|
@ -2270,6 +2276,12 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
{
|
||||
boolean madeGame = DBUtils.ROWID_NOTFOUND != m_missingDictRowId;
|
||||
if ( madeGame ) {
|
||||
// if ( R.id.games_game_reset == m_missingDictMenuId ) {
|
||||
// long[] rowIDs = { m_missingDictRowId };
|
||||
// doConfirmReset( rowIDs );
|
||||
// } else {
|
||||
// launchGame( m_missingDictRowId );
|
||||
// }
|
||||
// save in case checkWarnNoDict needs to set them
|
||||
long rowID = m_missingDictRowId;
|
||||
int menuID = m_missingDictMenuId;
|
||||
|
@ -2280,7 +2292,7 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
long[] rowIDs = { rowID };
|
||||
doConfirmReset( rowIDs );
|
||||
} else if ( checkWarnNoDict( rowID ) ) {
|
||||
GameUtils.launchGame( m_activity, rowID );
|
||||
GameUtils.launchGame( getDelegator(), rowID );
|
||||
}
|
||||
}
|
||||
return madeGame;
|
||||
|
@ -2288,9 +2300,16 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
|
||||
private void launchGame( long rowid, boolean invited )
|
||||
{
|
||||
// DbgUtils.logf( "launchGame(%d)", rowid );
|
||||
// if ( ! m_launchedGames.contains( rowid ) ) {
|
||||
// m_launchedGames.add( rowid );
|
||||
// m_delegator.launchGame( rowid, invited );
|
||||
if ( ! m_launchedGames.contains( rowid ) ) {
|
||||
m_launchedGames.add( rowid );
|
||||
GameUtils.launchGame( m_activity, rowid, invited );
|
||||
if ( m_adapter.inExpandedGroup( rowid ) ) {
|
||||
setSelGame( rowid );
|
||||
}
|
||||
GameUtils.launchGame( getDelegator(), rowid, invited );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2320,13 +2339,19 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
{
|
||||
GameSummary summary = (GameSummary)params[1];
|
||||
long rowid = (Long)params[0];
|
||||
DbgUtils.logf( "GamesListDelegate.doOpenGame(%d)", rowid );
|
||||
|
||||
if ( summary.conTypes.contains( CommsAddrRec.CommsConnType.COMMS_CONN_RELAY )
|
||||
&& summary.roomName.length() == 0 ) {
|
||||
Assert.fail();
|
||||
} else {
|
||||
if ( checkWarnNoDict( rowid ) ) {
|
||||
launchGame( rowid );
|
||||
try {
|
||||
if ( checkWarnNoDict( rowid ) ) {
|
||||
launchGame( rowid );
|
||||
}
|
||||
} catch ( GameLock.GameLockedException gle ) {
|
||||
DbgUtils.loge( gle );
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2465,11 +2490,12 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
|
||||
if ( doConfigure ) {
|
||||
// configure it
|
||||
GameConfigDelegate.editForResult( m_activity, RequestCode
|
||||
.CONFIG_GAME, rowID );
|
||||
GameConfigDelegate.editForResult( getDelegator(),
|
||||
RequestCode.CONFIG_GAME,
|
||||
rowID );
|
||||
} else {
|
||||
// launch it
|
||||
GameUtils.launchGame( m_activity, rowID );
|
||||
GameUtils.launchGame( getDelegator(), rowID );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/* -*- compile-command: "find-and-ant.sh debug install"; -*- */
|
||||
/*
|
||||
* Copyright 2014 - 2016 by Eric House (xwords@eehouse.org). All rights
|
||||
* reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package org.eehouse.android.xw4;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
public class GamesListFrag extends XWFragment {
|
||||
|
||||
@Override
|
||||
public void onCreate( Bundle sis )
|
||||
{
|
||||
super.onCreate( new GamesListDelegate( this, sis ), sis, true );
|
||||
}
|
||||
}
|
|
@ -69,5 +69,4 @@ public class ListDelegateBase extends DelegateBase {
|
|||
setListAdapter( adapter );
|
||||
listView.setSelectionFromTop( pos, top );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/* -*- compile-command: "find-and-ant.sh debug install"; -*- */
|
||||
/*
|
||||
* Copyright 2014 - 2016 by Eric House (xwords@eehouse.org). All rights
|
||||
* reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package org.eehouse.android.xw4;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.View;
|
||||
|
||||
public class Main extends Activity {
|
||||
|
||||
@Override
|
||||
public void onCreate( Bundle savedInstanceState )
|
||||
{
|
||||
super.onCreate( savedInstanceState );
|
||||
|
||||
if ( BuildConfig.DEBUG && XWApp.OFFER_DUALPANE ) {
|
||||
setContentView( R.layout.main );
|
||||
|
||||
findViewById( R.id.activity_button )
|
||||
.setOnClickListener( new OnClickListener() {
|
||||
@Override
|
||||
public void onClick( View v ) {
|
||||
startActivity( GamesListActivity.class );
|
||||
}
|
||||
} );
|
||||
findViewById( R.id.fragment_button )
|
||||
.setOnClickListener( new OnClickListener() {
|
||||
@Override
|
||||
public void onClick( View v ) {
|
||||
startActivity( FragActivity.class );
|
||||
}
|
||||
} );
|
||||
} else {
|
||||
startActivity( GamesListActivity.class );
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
private void startActivity( Class clazz )
|
||||
{
|
||||
startActivity( new Intent( this, clazz ) );
|
||||
}
|
||||
}
|
|
@ -50,7 +50,7 @@ public class MultiMsgSink implements TransportProcs {
|
|||
// rowID is used as token to identify game on relay. Anything that
|
||||
// uniquely identifies a game on a device would work
|
||||
public long getRowID() { return m_rowid; };
|
||||
public void setRowID( long rowID ) { m_rowid = rowID; };
|
||||
public MultiMsgSink setRowID( long rowID ) { m_rowid = rowID; return this; };
|
||||
|
||||
// These will be overridden by e.g. BTService which for sendViaBluetooth()
|
||||
// can just insert a message into its queue
|
||||
|
|
|
@ -61,7 +61,7 @@ public class MultiService {
|
|||
public enum MultiEvent { _INVALID,
|
||||
BAD_PROTO_BT,
|
||||
BAD_PROTO_SMS,
|
||||
APP_NOT_FOUND,
|
||||
APP_NOT_FOUND_BT,
|
||||
BT_ENABLED,
|
||||
BT_DISABLED,
|
||||
SCAN_DONE,
|
||||
|
@ -197,5 +197,4 @@ public class MultiService {
|
|||
}
|
||||
return downloaded;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -238,11 +238,8 @@ public class PrefsDelegate extends DelegateBase
|
|||
{
|
||||
if ( AlertDialog.BUTTON_POSITIVE == button
|
||||
&& action == Action.ENABLE_SMS_DO ) {
|
||||
boolean enabled = (Boolean)params[0];
|
||||
if ( enabled ) {
|
||||
XWPrefs.setSMSEnabled( m_activity, true );
|
||||
SMSCheckBoxPreference.setChecked();
|
||||
}
|
||||
XWPrefs.setSMSEnabled( m_activity, true );
|
||||
SMSCheckBoxPreference.setChecked();
|
||||
} else {
|
||||
super.dlgButtonClicked( action, button, params );
|
||||
}
|
||||
|
|
|
@ -54,6 +54,7 @@ import org.eehouse.android.xw4.jni.GameSummary;
|
|||
import org.eehouse.android.xw4.jni.LastMoveInfo;
|
||||
import org.eehouse.android.xw4.jni.UtilCtxt.DevIDType;
|
||||
import org.eehouse.android.xw4.jni.XwJNI;
|
||||
import org.eehouse.android.xw4.jni.JNIThread;
|
||||
import org.eehouse.android.xw4.loc.LocUtils;
|
||||
|
||||
public class RelayService extends XWService
|
||||
|
@ -248,22 +249,26 @@ public class RelayService extends XWService
|
|||
long[] rowids = DBUtils.getRowIDsFor( this, nli.gameID() );
|
||||
if ( (null == rowids || 0 == rowids.length)
|
||||
|| XWPrefs.getRelayInviteToSelfEnabled( this )) {
|
||||
CommsAddrRec addr = nli.makeAddrRec( this );
|
||||
// We can't pass a message sink, meaning we can't let the device
|
||||
// connect to the inviting game, because it needs to be open to
|
||||
// make the initial connection -- needs access to util. That
|
||||
// should be fixable -- eventually.
|
||||
RelayMsgSink sink = new RelayMsgSink();
|
||||
long rowid = GameUtils.makeNewMultiGame( this, nli, sink,
|
||||
getUtilCtxt() );
|
||||
if ( DBUtils.ROWID_NOTFOUND != rowid ) {
|
||||
if ( null != nli.gameName && 0 < nli.gameName.length() ) {
|
||||
DBUtils.setName( this, rowid, nli.gameName );
|
||||
|
||||
if ( DictLangCache.haveDict( this, nli.lang, nli.dict ) ) {
|
||||
long rowid = GameUtils.makeNewMultiGame( this, nli,
|
||||
new RelayMsgSink(),
|
||||
getUtilCtxt() );
|
||||
if ( DBUtils.ROWID_NOTFOUND != rowid ) {
|
||||
if ( null != nli.gameName && 0 < nli.gameName.length() ) {
|
||||
DBUtils.setName( this, rowid, nli.gameName );
|
||||
}
|
||||
String body = LocUtils.getString( this,
|
||||
R.string.new_relay_body );
|
||||
GameUtils.postInvitedNotification( this, nli.gameID(), body,
|
||||
rowid );
|
||||
}
|
||||
String body = LocUtils.getString( this,
|
||||
R.string.new_relay_body );
|
||||
GameUtils.postInvitedNotification( this, nli.gameID(), body,
|
||||
rowid );
|
||||
} else {
|
||||
Intent intent = MultiService
|
||||
.makeMissingDictIntent( this, nli,
|
||||
DictFetchOwner.OWNER_RELAY );
|
||||
MultiService.postMissingDictNotification( this, intent,
|
||||
nli.gameID() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -312,6 +317,12 @@ public class RelayService extends XWService
|
|||
return intent;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MultiMsgSink getSink( long rowid )
|
||||
{
|
||||
return new RelayMsgSink().setRowID( rowid );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate()
|
||||
{
|
||||
|
@ -395,7 +406,7 @@ public class RelayService extends XWService
|
|||
String relayID = intent.getStringExtra( RELAY_ID );
|
||||
sendNoConnMessage( rowid, relayID, msg );
|
||||
} else {
|
||||
feedMessage( rowid, msg );
|
||||
receiveMessage( this, rowid, null, msg, s_addr );
|
||||
}
|
||||
break;
|
||||
case INVITE:
|
||||
|
@ -466,6 +477,15 @@ public class RelayService extends XWService
|
|||
}
|
||||
}
|
||||
|
||||
// private void setupNotification( long rowid )
|
||||
// {
|
||||
// Intent intent = GamesListDelegate.makeRowidIntent( this, rowid );
|
||||
// String msg = LocUtils.getString( this, R.string.notify_body_fmt,
|
||||
// GameUtils.getName( this, rowid ) );
|
||||
// Utils.postNotification( this, intent, R.string.notify_title,
|
||||
// msg, (int)rowid );
|
||||
// }
|
||||
|
||||
private boolean startFetchThreadIf()
|
||||
{
|
||||
// DbgUtils.logf( "startFetchThreadIf()" );
|
||||
|
@ -982,27 +1002,6 @@ public class RelayService extends XWService
|
|||
return devid;
|
||||
}
|
||||
|
||||
private void feedMessage( long rowid, byte[] msg )
|
||||
{
|
||||
DbgUtils.logdf( "RelayService::feedMessage: %d bytes for rowid %d",
|
||||
msg.length, rowid );
|
||||
if ( BoardDelegate.feedMessage( rowid, msg, s_addr ) ) {
|
||||
DbgUtils.logdf( "feedMessage: board ate it" );
|
||||
// do nothing
|
||||
} else {
|
||||
RelayMsgSink sink = new RelayMsgSink();
|
||||
sink.setRowID( rowid );
|
||||
BackMoveResult bmr = new BackMoveResult();
|
||||
boolean[] isLocalP = new boolean[1];
|
||||
if ( GameUtils.feedMessage( this, rowid, msg, s_addr,
|
||||
sink, bmr, isLocalP ) ) {
|
||||
GameUtils.postMoveNotification( this, rowid, bmr, isLocalP[0] );
|
||||
} else {
|
||||
DbgUtils.logdf( "feedMessage(): background dropped it" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fetchAndProcess()
|
||||
{
|
||||
long[][] rowIDss = new long[1][];
|
||||
|
@ -1026,33 +1025,14 @@ public class RelayService extends XWService
|
|||
boolean[] isLocalP = new boolean[1];
|
||||
for ( int ii = 0; ii < nameCount; ++ii ) {
|
||||
byte[][] forOne = msgs[ii];
|
||||
|
||||
// if game has messages, open it and feed 'em to it.
|
||||
if ( null != forOne ) {
|
||||
BackMoveResult bmr = new BackMoveResult();
|
||||
sink.setRowID( rowIDs[ii] );
|
||||
// since BoardDelegate.feedMessages can't know:
|
||||
isLocalP[0] = false;
|
||||
if ( BoardDelegate.feedMessages( rowIDs[ii], forOne, s_addr )
|
||||
|| GameUtils.feedMessages( this, rowIDs[ii],
|
||||
forOne, s_addr,
|
||||
sink, bmr, isLocalP ) ) {
|
||||
idsWMsgs.add( relayIDs[ii] );
|
||||
bmrs.add( bmr );
|
||||
isLocals.add( isLocalP[0] );
|
||||
} else {
|
||||
DbgUtils.logf( "RelayService.process(): message for %s (rowid %d)"
|
||||
+ " not consumed", relayIDs[ii], rowIDs[ii] );
|
||||
long rowid = rowIDs[ii];
|
||||
sink.setRowID( rowid );
|
||||
for ( byte[] msg : forOne ) {
|
||||
receiveMessage( this, rowid, sink, msg, s_addr );
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( 0 < idsWMsgs.size() ) {
|
||||
String[] tmp = new String[idsWMsgs.size()];
|
||||
idsWMsgs.toArray( tmp );
|
||||
BackMoveResult[] bmrsa = new BackMoveResult[bmrs.size()];
|
||||
bmrs.toArray( bmrsa );
|
||||
setupNotifications( tmp, bmrsa, isLocals );
|
||||
}
|
||||
sink.send( this );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,6 +85,9 @@ public class SMSInviteDelegate extends InviteDelegate {
|
|||
|
||||
protected void init( Bundle savedInstanceState )
|
||||
{
|
||||
// super.init( R.id.button_invite, R.id.button_add,
|
||||
// R.id.button_clear, R.id.invite_desc,
|
||||
// R.string.invite_sms_desc_fmt );
|
||||
String msg = getString( R.string.button_invite );
|
||||
msg = getQuantityString( R.plurals.invite_sms_desc_fmt, m_nMissing,
|
||||
m_nMissing, msg );
|
||||
|
@ -376,24 +379,6 @@ public class SMSInviteDelegate extends InviteDelegate {
|
|||
saveAndRebuild();
|
||||
}
|
||||
|
||||
private void clearIfSingle()
|
||||
{
|
||||
if ( 1 == m_nMissing ) {
|
||||
int count = m_adapter.getCount();
|
||||
for ( int ii = count - 1; ii >= 0; --ii ) {
|
||||
PhoneRec rec = m_phoneRecs.get( ii );
|
||||
if ( rec.m_isChecked ) {
|
||||
rec.m_isChecked = false;
|
||||
}
|
||||
}
|
||||
post( new Runnable() {
|
||||
public void run() {
|
||||
rebuildList( false );
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
private class PhoneRec {
|
||||
public String m_phone;
|
||||
public String m_name;
|
||||
|
@ -449,7 +434,6 @@ public class SMSInviteDelegate extends InviteDelegate {
|
|||
new CompoundButton.OnCheckedChangeListener() {
|
||||
public void onCheckedChanged( CompoundButton bv,
|
||||
boolean isChecked ) {
|
||||
clearIfSingle();
|
||||
m_phoneRecs.get(position).m_isChecked = isChecked;
|
||||
tryEnable();
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ import java.util.Set;
|
|||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.eehouse.android.xw4.XWService.ReceiveResult;
|
||||
import org.eehouse.android.xw4.GameUtils.BackMoveResult;
|
||||
import org.eehouse.android.xw4.MultiService.DictFetchOwner;
|
||||
import org.eehouse.android.xw4.MultiService.MultiEvent;
|
||||
|
@ -62,6 +63,7 @@ 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.jni.JNIThread;
|
||||
import org.eehouse.android.xw4.loc.LocUtils;
|
||||
|
||||
public class SMSService extends XWService {
|
||||
|
@ -287,6 +289,12 @@ public class SMSService extends XWService {
|
|||
return s_showToasts;
|
||||
}
|
||||
|
||||
@Override // abstract
|
||||
protected MultiMsgSink getSink( long rowid )
|
||||
{
|
||||
return new SMSMsgSink( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate()
|
||||
{
|
||||
|
@ -703,24 +711,9 @@ public class SMSService extends XWService {
|
|||
|
||||
private void feedMessage( int gameID, byte[] msg, CommsAddrRec addr )
|
||||
{
|
||||
long[] rowids = DBUtils.getRowIDsFor( this, gameID );
|
||||
if ( null == rowids || 0 == rowids.length ) {
|
||||
ReceiveResult rslt = receiveMessage( this, gameID, null, msg, addr );
|
||||
if ( ReceiveResult.GAME_GONE == rslt ) {
|
||||
sendDiedPacket( addr.sms_phone, gameID );
|
||||
} else {
|
||||
boolean[] isLocalP = new boolean[1];
|
||||
for ( long rowid : rowids ) {
|
||||
if ( BoardDelegate.feedMessage( rowid, msg, addr ) ) {
|
||||
// do nothing
|
||||
} else {
|
||||
SMSMsgSink sink = new SMSMsgSink( this );
|
||||
BackMoveResult bmr = new BackMoveResult();
|
||||
if ( GameUtils.feedMessage( this, rowid, msg, addr,
|
||||
sink, bmr, isLocalP ) ) {
|
||||
GameUtils.postMoveNotification( this, rowid, bmr,
|
||||
isLocalP[0] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,8 +19,10 @@
|
|||
|
||||
package org.eehouse.android.xw4;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.ListActivity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
@ -291,6 +293,7 @@ public class StudyListDelegate extends ListDelegateBase
|
|||
}
|
||||
}
|
||||
|
||||
DbgUtils.logf( "creating studylist adapter" );
|
||||
ArrayAdapter<String> adapter = new
|
||||
ArrayAdapter<String>( m_activity,
|
||||
android.R.layout.simple_spinner_item,
|
||||
|
@ -342,10 +345,11 @@ public class StudyListDelegate extends ListDelegateBase
|
|||
setTitleBar();
|
||||
}
|
||||
|
||||
public static void launchOrAlert( Activity activity, int lang,
|
||||
public static void launchOrAlert( Delegator delegator, int lang,
|
||||
DlgDelegate.HasDlgDelegate dlg )
|
||||
{
|
||||
String msg = null;
|
||||
Activity activity = delegator.getActivity();
|
||||
if ( 0 == DBUtils.studyListLangs( activity ).length ) {
|
||||
msg = LocUtils.getString( activity, R.string.study_no_lists );
|
||||
} else if ( NO_LANG != lang &&
|
||||
|
@ -359,9 +363,14 @@ public class StudyListDelegate extends ListDelegateBase
|
|||
bundle.putInt( START_LANG, lang );
|
||||
}
|
||||
|
||||
Intent intent = new Intent( activity, StudyListActivity.class );
|
||||
intent.putExtras( bundle );
|
||||
activity.startActivity( intent );
|
||||
if ( activity instanceof FragActivity ) {
|
||||
StudyListFrag frag = new StudyListFrag();
|
||||
((FragActivity)activity).addFragment( frag, bundle, delegator );
|
||||
} else {
|
||||
Intent intent = new Intent( activity, StudyListActivity.class );
|
||||
intent.putExtras( bundle );
|
||||
activity.startActivity( intent );
|
||||
}
|
||||
}
|
||||
|
||||
if ( null != msg ) {
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/* -*- compile-command: "find-and-ant.sh debug install"; -*- */
|
||||
/*
|
||||
* Copyright 2014 - 2016 by Eric House (xwords@eehouse.org). All rights
|
||||
* reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package org.eehouse.android.xw4;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
public class StudyListFrag extends XWFragment {
|
||||
|
||||
@Override
|
||||
public void onCreate( Bundle sis )
|
||||
{
|
||||
super.onCreate( new StudyListDelegate( this, sis ), sis, true );
|
||||
}
|
||||
}
|
|
@ -72,17 +72,12 @@ public class Toolbar {
|
|||
private DlgDelegate.HasDlgDelegate m_dlgDlgt;
|
||||
private LinearLayout m_layout;
|
||||
private boolean m_visible;
|
||||
private Boolean m_isPortrait;
|
||||
|
||||
private enum ORIENTATION { ORIENT_PORTRAIT, ORIENT_LANDSCAPE };
|
||||
private ORIENTATION m_curOrient = null;
|
||||
|
||||
public Toolbar( Activity activity, HasDlgDelegate dlgDlgt,
|
||||
boolean isLandscape )
|
||||
public Toolbar( Activity activity, HasDlgDelegate dlgDlgt )
|
||||
{
|
||||
m_activity = activity;
|
||||
m_dlgDlgt = dlgDlgt;
|
||||
|
||||
setIsLandscape( isLandscape );
|
||||
}
|
||||
|
||||
public void setVisible( boolean visible )
|
||||
|
@ -123,18 +118,10 @@ public class Toolbar {
|
|||
setLongClickListener( index, listener );
|
||||
}
|
||||
|
||||
private void setIsLandscape( boolean landscape )
|
||||
protected void setIsPortrait( boolean isPortrait )
|
||||
{
|
||||
if ( landscape && m_curOrient == ORIENTATION.ORIENT_LANDSCAPE ) {
|
||||
// do nothing
|
||||
} else if ( !landscape && m_curOrient == ORIENTATION.ORIENT_PORTRAIT ) {
|
||||
// do nothing
|
||||
} else {
|
||||
if ( landscape ) {
|
||||
m_curOrient = ORIENTATION.ORIENT_LANDSCAPE;
|
||||
} else {
|
||||
m_curOrient = ORIENTATION.ORIENT_PORTRAIT;
|
||||
}
|
||||
if ( null == m_isPortrait || m_isPortrait != isPortrait ) {
|
||||
m_isPortrait = isPortrait;
|
||||
doShowHide();
|
||||
}
|
||||
}
|
||||
|
@ -151,20 +138,21 @@ public class Toolbar {
|
|||
|
||||
private void doShowHide()
|
||||
{
|
||||
Assert.assertTrue( null != m_curOrient );
|
||||
boolean isLandscape = ORIENTATION.ORIENT_LANDSCAPE == m_curOrient;
|
||||
Assert.assertTrue( null != m_isPortrait );
|
||||
if ( null == m_layout ) {
|
||||
m_layout = (LinearLayout)LocUtils.inflate( m_activity, R.layout.toolbar );
|
||||
m_layout.setOrientation(ORIENTATION.ORIENT_PORTRAIT == m_curOrient
|
||||
? LinearLayout.HORIZONTAL : LinearLayout.VERTICAL );
|
||||
} else {
|
||||
((ViewGroup)m_layout.getParent()).removeView( m_layout );
|
||||
}
|
||||
m_layout.setOrientation( m_isPortrait ?
|
||||
LinearLayout.HORIZONTAL : LinearLayout.VERTICAL );
|
||||
|
||||
int id = isLandscape ? R.id.tbar_parent_vert : R.id.tbar_parent_hor;
|
||||
ViewGroup scroller = (ViewGroup)m_activity.findViewById( id );
|
||||
if ( null != scroller ) {
|
||||
// Google's had reports of a crash adding second view
|
||||
scroller.removeAllViews();
|
||||
scroller.addView( m_layout ); // failing
|
||||
}
|
||||
int id = m_isPortrait ? R.id.tbar_parent_hor : R.id.tbar_parent_vert;
|
||||
ViewGroup scroller = (ViewGroup)m_activity.findViewById( id );
|
||||
if ( null != scroller ) {
|
||||
// Google's had reports of a crash adding second view
|
||||
scroller.removeAllViews();
|
||||
scroller.addView( m_layout );
|
||||
}
|
||||
|
||||
m_layout.setVisibility( m_visible? View.VISIBLE : View.GONE );
|
||||
|
|
|
@ -35,16 +35,15 @@ import android.content.pm.PackageManager;
|
|||
import android.content.pm.ResolveInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.database.Cursor;
|
||||
import android.media.RingtoneManager;
|
||||
import android.net.Uri;
|
||||
import android.provider.ContactsContract.PhoneLookup;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import java.io.File;
|
||||
|
@ -239,6 +238,15 @@ public class Utils {
|
|||
nm.cancel( id );
|
||||
}
|
||||
|
||||
public static void playNotificationSound( Context context )
|
||||
{
|
||||
if ( CommonPrefs.getSoundNotify( context ) ) {
|
||||
Uri uri = RingtoneManager
|
||||
.getDefaultUri( RingtoneManager.TYPE_NOTIFICATION );
|
||||
RingtoneManager.getRingtone( context, uri ).play();
|
||||
}
|
||||
}
|
||||
|
||||
// adapted from
|
||||
// http://stackoverflow.com/questions/2174048/how-to-look-up-a-contacts-name-from-their-phone-number-on-android
|
||||
public static String phoneToContact( Context context, String phone,
|
||||
|
|
|
@ -22,6 +22,7 @@ package org.eehouse.android.xw4;
|
|||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.ContextMenu;
|
||||
|
@ -34,6 +35,8 @@ import android.widget.ListView;
|
|||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
public class XWActivity extends Activity implements Delegator {
|
||||
|
||||
private DelegateBase m_dlgt;
|
||||
|
@ -176,6 +179,13 @@ public class XWActivity extends Activity implements Delegator {
|
|||
m_dlgt.prepareDialog( DlgID.values()[id], dialog );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged( Configuration newConfig )
|
||||
{
|
||||
m_dlgt.orientationChanged();
|
||||
super.onConfigurationChanged( newConfig );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult( int requestCode, int resultCode,
|
||||
Intent data )
|
||||
|
|
|
@ -38,14 +38,16 @@ public class XWApp extends Application {
|
|||
public static final boolean REMATCH_SUPPORTED = true;
|
||||
public static final boolean RELAYINVITE_SUPPORTED = false;
|
||||
public static final boolean ATTACH_SUPPORTED = false;
|
||||
public static final boolean DEBUG_LOCKS = false;
|
||||
public static final boolean LOG_LIFECYLE = false;
|
||||
public static final boolean LOG_LIFECYLE = true;
|
||||
public static final boolean DEBUG_EXP_TIMERS = false;
|
||||
public static final boolean GCM_IGNORED = false;
|
||||
public static final boolean UDP_ENABLED = true;
|
||||
public static final boolean SMS_INVITE_ENABLED = true;
|
||||
public static final boolean LOCUTILS_ENABLED = false;
|
||||
public static final boolean CONTEXT_MENUS_ENABLED = true;
|
||||
public static final boolean OFFER_DUALPANE = false;
|
||||
// BT class "COMPUTERS" includes tablets like the Nexus 9
|
||||
public static final boolean BT_SCAN_COMPUTERS = true;
|
||||
|
||||
public static final String SMS_PUBLIC_HEADER = "-XW4";
|
||||
public static final int MAX_TRAY_TILES = 7; // comtypes.h
|
||||
|
@ -53,10 +55,12 @@ public class XWApp extends Application {
|
|||
|
||||
private static UUID s_UUID = null;
|
||||
private static Boolean s_onEmulator = null;
|
||||
private static Context s_context = null;
|
||||
|
||||
@Override
|
||||
public void onCreate()
|
||||
{
|
||||
s_context = this;
|
||||
super.onCreate();
|
||||
|
||||
// This one line should always get logged even if logging is
|
||||
|
@ -117,4 +121,6 @@ public class XWApp extends Application {
|
|||
}
|
||||
return s_onEmulator;
|
||||
}
|
||||
|
||||
public static Context getContext() { return s_context; }
|
||||
}
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
/* -*- compile-command: "find-and-ant.sh debug install"; -*- */
|
||||
/*
|
||||
* Copyright 2014 by Eric House (xwords@eehouse.org). All rights
|
||||
* reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package org.eehouse.android.xw4;
|
||||
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.ListView;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
public class XWFragment extends Fragment
|
||||
implements Delegator,
|
||||
FragActivity.OrientChangeListener {
|
||||
|
||||
private DelegateBase m_dlgt;
|
||||
private boolean m_hasOptionsMenu = false;
|
||||
|
||||
protected void onCreate( DelegateBase dlgt, Bundle sis, boolean hasOptionsMenu )
|
||||
{
|
||||
m_hasOptionsMenu = hasOptionsMenu;
|
||||
this.onCreate( dlgt, sis );
|
||||
}
|
||||
|
||||
protected void onCreate( DelegateBase dlgt, Bundle sis )
|
||||
{
|
||||
DbgUtils.logdf( "%s.onCreate() called", this.getClass().getName() );
|
||||
super.onCreate( sis );
|
||||
m_dlgt = dlgt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView( LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState )
|
||||
{
|
||||
DbgUtils.logdf( "%s.onCreateView() called", this.getClass().getName() );
|
||||
return m_dlgt.inflateView( inflater, container );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated( Bundle savedInstanceState )
|
||||
{
|
||||
DbgUtils.logdf( "%s.onActivityCreated() called", this.getClass().getName() );
|
||||
m_dlgt.init( savedInstanceState );
|
||||
super.onActivityCreated( savedInstanceState );
|
||||
if ( m_hasOptionsMenu ) {
|
||||
setHasOptionsMenu( true );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause()
|
||||
{
|
||||
DbgUtils.logdf( "%s.onPause() called", this.getClass().getName() );
|
||||
m_dlgt.onPause();
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume()
|
||||
{
|
||||
super.onResume();
|
||||
m_dlgt.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart()
|
||||
{
|
||||
DbgUtils.logdf( "%s.onStart() called", this.getClass().getName() );
|
||||
super.onStart();
|
||||
m_dlgt.onStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop()
|
||||
{
|
||||
DbgUtils.logdf( "%s.onStop() called", this.getClass().getName() );
|
||||
m_dlgt.onStop();
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy()
|
||||
{
|
||||
DbgUtils.logdf( "%s.onDestroy() called", this.getClass().getName() );
|
||||
m_dlgt.onDestroy();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareOptionsMenu( Menu menu )
|
||||
{
|
||||
m_dlgt.onPrepareOptionsMenu( menu );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu( Menu menu, MenuInflater inflater )
|
||||
{
|
||||
m_dlgt.onCreateOptionsMenu( menu, inflater );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected( MenuItem item )
|
||||
{
|
||||
return m_dlgt.onOptionsItemSelected( item );
|
||||
}
|
||||
|
||||
public void finish()
|
||||
{
|
||||
Assert.fail();
|
||||
}
|
||||
|
||||
// FragActivity.OrientChangeListener
|
||||
public void orientationChanged()
|
||||
{
|
||||
m_dlgt.orientationChanged();
|
||||
}
|
||||
|
||||
public ListView getListView()
|
||||
{
|
||||
ListView view = (ListView)m_dlgt.findViewById( android.R.id.list );
|
||||
return view;
|
||||
}
|
||||
|
||||
public void setListAdapter( ListAdapter adapter )
|
||||
{
|
||||
getListView().setAdapter( adapter );
|
||||
}
|
||||
|
||||
public ListAdapter getListAdapter()
|
||||
{
|
||||
return getListView().getAdapter();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -21,17 +21,23 @@
|
|||
package org.eehouse.android.xw4;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.eehouse.android.xw4.MultiService.MultiEvent;
|
||||
import org.eehouse.android.xw4.jni.CommsAddrRec;
|
||||
import org.eehouse.android.xw4.jni.JNIThread;
|
||||
import org.eehouse.android.xw4.jni.UtilCtxt;
|
||||
import org.eehouse.android.xw4.jni.UtilCtxtImpl;
|
||||
|
||||
public class XWService extends Service {
|
||||
class XWService extends Service {
|
||||
public static enum ReceiveResult { OK, GAME_GONE, UNCONSUMED };
|
||||
|
||||
protected static MultiService s_srcMgr = null;
|
||||
private static Set<String> s_seen = new HashSet<String>();
|
||||
|
@ -85,4 +91,56 @@ public class XWService extends Service {
|
|||
}
|
||||
return m_utilCtxt;
|
||||
}
|
||||
|
||||
// Meant to be overridden
|
||||
protected MultiMsgSink getSink( long rowid ) { Assert.fail(); return null; }
|
||||
|
||||
protected ReceiveResult receiveMessage( Context context, int gameID,
|
||||
MultiMsgSink sink, byte[] msg,
|
||||
CommsAddrRec addr )
|
||||
{
|
||||
ReceiveResult result;
|
||||
long[] rowids = DBUtils.getRowIDsFor( context, gameID );
|
||||
if ( null == rowids || 0 == rowids.length ) {
|
||||
result = ReceiveResult.GAME_GONE;
|
||||
} else {
|
||||
result = ReceiveResult.UNCONSUMED;
|
||||
for ( long rowid : rowids ) {
|
||||
if ( receiveMessage( context, rowid, sink, msg, addr ) ) {
|
||||
result = ReceiveResult.OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected boolean receiveMessage( Context context, long rowid,
|
||||
MultiMsgSink sink, byte[] msg,
|
||||
CommsAddrRec addr )
|
||||
{
|
||||
boolean allConsumed = true;
|
||||
boolean[] isLocalP = new boolean[1];
|
||||
JNIThread jniThread = JNIThread.getRetained( rowid, false );
|
||||
boolean consumed = false;
|
||||
if ( null != jniThread ) {
|
||||
consumed = true;
|
||||
jniThread.receive( msg, addr ).release();
|
||||
} else {
|
||||
GameUtils.BackMoveResult bmr =
|
||||
new GameUtils.BackMoveResult();
|
||||
if ( null == sink ) {
|
||||
sink = getSink( rowid );
|
||||
}
|
||||
if ( GameUtils.feedMessage( context, rowid, msg, addr,
|
||||
sink, bmr, isLocalP ) ) {
|
||||
consumed = true;
|
||||
GameUtils.postMoveNotification( context, rowid, bmr,
|
||||
isLocalP[0] );
|
||||
}
|
||||
}
|
||||
if ( allConsumed && !consumed ) {
|
||||
allConsumed = false;
|
||||
}
|
||||
return allConsumed;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnTypeSet;
|
|||
public interface BoardHandler {
|
||||
|
||||
void startHandling( Activity parent, JNIThread thread,
|
||||
XwJNI.GamePtr gamePtr, CurGameInfo gi,
|
||||
CommsConnTypeSet connTypes );
|
||||
|
||||
void stopHandling();
|
||||
}
|
||||
|
|
|
@ -295,6 +295,24 @@ public class CurGameInfo {
|
|||
return !consistent;
|
||||
}
|
||||
|
||||
public String[] playerNames()
|
||||
{
|
||||
String[] names = new String[nPlayers];
|
||||
for ( int ii = 0; ii < nPlayers; ++ii ) {
|
||||
names[ii] = players[ii].name;
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
public boolean[] playersLocal()
|
||||
{
|
||||
boolean[] locs = new boolean[nPlayers];
|
||||
for ( int ii = 0; ii < nPlayers; ++ii ) {
|
||||
locs[ii] = players[ii].isLocal;
|
||||
}
|
||||
return locs;
|
||||
}
|
||||
|
||||
public String[] visibleNames( boolean withDicts )
|
||||
{
|
||||
String nameFmt = withDicts?
|
||||
|
|
|
@ -30,11 +30,17 @@ import android.os.Message;
|
|||
import java.lang.InterruptedException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eehouse.android.xw4.CommsTransport;
|
||||
import org.eehouse.android.xw4.ConnStatusHandler;
|
||||
import org.eehouse.android.xw4.DBUtils;
|
||||
import org.eehouse.android.xw4.DbgUtils;
|
||||
import org.eehouse.android.xw4.DictUtils;
|
||||
import org.eehouse.android.xw4.GameLock;
|
||||
import org.eehouse.android.xw4.GameUtils;
|
||||
import org.eehouse.android.xw4.R;
|
||||
|
@ -49,6 +55,21 @@ import junit.framework.Assert;
|
|||
|
||||
public class JNIThread extends Thread {
|
||||
|
||||
private static Set<JNIThread> s_curThreads = new HashSet<JNIThread>();
|
||||
|
||||
public static JNIThread getCurrent() {
|
||||
JNIThread result = null;
|
||||
synchronized( s_curThreads ) {
|
||||
// DbgUtils.logf( "JNIThread.getCurrent(): have %d threads",
|
||||
// s_curThreads.size() );
|
||||
if ( 1 == s_curThreads.size() ) {
|
||||
result = s_curThreads.iterator().next();
|
||||
}
|
||||
}
|
||||
// DbgUtils.logf( "JNIThread.getCurrent() => %H", result );
|
||||
return result;
|
||||
}
|
||||
|
||||
public enum JNICmd { CMD_NONE,
|
||||
// CMD_RUN,
|
||||
CMD_DRAW,
|
||||
|
@ -134,7 +155,7 @@ public class JNIThread extends Thread {
|
|||
private boolean m_stopped = false;
|
||||
private boolean m_saveOnStop = false;
|
||||
private GamePtr m_jniGamePtr;
|
||||
private byte[] m_gameAtStart;
|
||||
private byte[] m_lastSavedState;
|
||||
private GameLock m_lock;
|
||||
private Context m_context;
|
||||
private CurGameInfo m_gi;
|
||||
|
@ -143,6 +164,10 @@ public class JNIThread extends Thread {
|
|||
private static final int kMinDivWidth = 10;
|
||||
private int m_connsIconID = 0;
|
||||
private String m_newDict = null;
|
||||
private long m_rowid;
|
||||
private int m_refCount;
|
||||
private CommsTransport m_xport;
|
||||
private GameSummary m_summary;
|
||||
|
||||
private LinkedBlockingQueue<QueueElem> m_queue;
|
||||
|
||||
|
@ -156,22 +181,77 @@ public class JNIThread extends Thread {
|
|||
Object[] m_args;
|
||||
}
|
||||
|
||||
public JNIThread( GamePtr gamePtr, byte[] gameAtStart, CurGameInfo gi,
|
||||
SyncedDraw drawer, GameLock lock, Context context,
|
||||
Handler handler )
|
||||
private JNIThread( long rowid )
|
||||
{
|
||||
m_jniGamePtr = gamePtr;
|
||||
m_gameAtStart = gameAtStart;
|
||||
m_gi = gi;
|
||||
m_drawer = drawer;
|
||||
m_lock = lock;
|
||||
m_context = context;
|
||||
m_handler = handler;
|
||||
|
||||
m_rowid = rowid;
|
||||
m_queue = new LinkedBlockingQueue<QueueElem>();
|
||||
}
|
||||
|
||||
public JNIThread configure( Context context, SyncedDraw drawer,
|
||||
UtilCtxtImpl utils,
|
||||
TransportProcs.TPMsgHandler xportHandler,
|
||||
Handler handler )
|
||||
{
|
||||
m_context = context;
|
||||
m_drawer = drawer;
|
||||
m_handler = handler;
|
||||
|
||||
public void waitToStop( boolean save )
|
||||
if ( null == m_lock ) {
|
||||
m_lock = new GameLock( m_rowid, true ).lock();
|
||||
} else {
|
||||
m_jniGamePtr.release(); // let the old game copy go
|
||||
}
|
||||
|
||||
// If this isn't true then the queue has to be allowed to empty,
|
||||
// working on the old game state, before we can re-use any of this.
|
||||
Assert.assertTrue( 0 == m_queue.size() );
|
||||
|
||||
m_jniGamePtr = XwJNI.initJNI( m_rowid );
|
||||
|
||||
String[] dictNames = GameUtils.dictNames( context, m_lock );
|
||||
DictUtils.DictPairs pairs = DictUtils.openDicts( context, dictNames );
|
||||
Assert.assertFalse( pairs.anyMissing( dictNames ) ); // PENDING
|
||||
|
||||
byte[] stream = GameUtils.savedGame( context, m_lock );
|
||||
Assert.assertNotNull( stream );
|
||||
m_gi = new CurGameInfo( context );
|
||||
m_gi.setName( DBUtils.getName( context, m_rowid ) );
|
||||
XwJNI.gi_from_stream( m_gi, stream );
|
||||
|
||||
m_summary = DBUtils.getSummary( context, m_lock );
|
||||
|
||||
if ( m_gi.serverRole != DeviceRole.SERVER_STANDALONE ) {
|
||||
m_xport = new CommsTransport( context, xportHandler, m_rowid,
|
||||
m_gi.serverRole );
|
||||
m_xport.setReceiver( this );
|
||||
}
|
||||
|
||||
CommonPrefs cp = CommonPrefs.get( context );
|
||||
JNIUtils jniUtils = JNIUtilsImpl.get( context );
|
||||
if ( null == stream ||
|
||||
! XwJNI.game_makeFromStream( m_jniGamePtr, stream,
|
||||
m_gi, dictNames,
|
||||
pairs.m_bytes,
|
||||
pairs.m_paths,
|
||||
m_gi.langName(),
|
||||
utils, jniUtils,
|
||||
null, cp, m_xport ) ) {
|
||||
XwJNI.game_makeNewGame( m_jniGamePtr, m_gi, dictNames,
|
||||
pairs.m_bytes, pairs.m_paths,
|
||||
m_gi.langName(), utils, jniUtils,
|
||||
null, cp, m_xport );
|
||||
}
|
||||
|
||||
m_lastSavedState = stream;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GamePtr getGamePtr() { return m_jniGamePtr; }
|
||||
public CurGameInfo getGI() { return m_gi; }
|
||||
public GameSummary getSummary() { return m_summary; }
|
||||
public GameLock getLock() { return m_lock; }
|
||||
|
||||
private void waitToStop( boolean save )
|
||||
{
|
||||
synchronized ( this ) {
|
||||
m_stopped = true;
|
||||
|
@ -188,6 +268,9 @@ public class JNIThread extends Thread {
|
|||
} catch ( java.lang.InterruptedException ie ) {
|
||||
DbgUtils.loge( ie );
|
||||
}
|
||||
// m_jniGamePtr.release();
|
||||
// m_jniGamePtr = null;
|
||||
m_lock.unlock();
|
||||
}
|
||||
|
||||
public boolean busy()
|
||||
|
@ -297,8 +380,14 @@ public class JNIThread extends Thread {
|
|||
m_gi.dictName = m_newDict;
|
||||
}
|
||||
byte[] state = XwJNI.game_saveToStream( m_jniGamePtr, m_gi );
|
||||
if ( Arrays.equals( m_gameAtStart, state ) ) {
|
||||
// DbgUtils.logf( "no change in game; can skip saving" );
|
||||
boolean arraysEqual = Arrays.equals( m_lastSavedState, state );
|
||||
boolean hashesEqual = Arrays.hashCode( m_lastSavedState) == Arrays.hashCode(state);
|
||||
DbgUtils.logf( "arraysEqual: %b; hashesEqual: %b", arraysEqual, hashesEqual );
|
||||
// PENDING: once certain this is true, stop saving the full array and
|
||||
// instead save the hash. Also, update it after each save.
|
||||
Assert.assertTrue( arraysEqual == hashesEqual );
|
||||
if ( Arrays.equals( m_lastSavedState, state ) ) {
|
||||
DbgUtils.logdf( "JNIThread.save_jni(): no change in game; can skip saving" );
|
||||
} else {
|
||||
synchronized( this ) {
|
||||
Assert.assertNotNull( m_lock );
|
||||
|
@ -308,10 +397,27 @@ public class JNIThread extends Thread {
|
|||
DBUtils.saveSummary( m_context, m_lock, summary );
|
||||
// There'd better be no way for saveGame above to fail!
|
||||
XwJNI.game_saveSucceeded( m_jniGamePtr );
|
||||
m_lastSavedState = state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean m_running = false;
|
||||
public void startOnce()
|
||||
{
|
||||
if ( !m_running ) {
|
||||
m_running = true;
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
public void setDaemonOnce( boolean val )
|
||||
{
|
||||
if ( !m_running ) {
|
||||
setDaemon( val );
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("fallthrough")
|
||||
public void run()
|
||||
{
|
||||
|
@ -340,11 +446,6 @@ public class JNIThread extends Thread {
|
|||
continue;
|
||||
}
|
||||
save_jni();
|
||||
// This is gross: we take the relay connection down
|
||||
// then bring it right back up again each time there's
|
||||
// a message received (to save any state changes it
|
||||
// brought). There must be a better way.
|
||||
// XwJNI.comms_start( m_jniGamePtr );
|
||||
break;
|
||||
|
||||
case CMD_DRAW:
|
||||
|
@ -609,20 +710,31 @@ public class JNIThread extends Thread {
|
|||
} else {
|
||||
DbgUtils.logf( "JNIThread.run(): exiting without saving" );
|
||||
}
|
||||
XwJNI.threadDone();
|
||||
m_jniGamePtr.release();
|
||||
m_jniGamePtr = null;
|
||||
// XwJNI.threadDone();
|
||||
} // run
|
||||
|
||||
public void handleBkgrnd( JNICmd cmd, Object... args )
|
||||
{
|
||||
QueueElem elem = new QueueElem( cmd, false, args );
|
||||
// DbgUtils.logf( "adding: %s", cmd.toString() );
|
||||
m_queue.add( elem );
|
||||
m_queue.add( new QueueElem( cmd, false, args ) );
|
||||
}
|
||||
|
||||
public JNIThread receive( byte[] msg, CommsAddrRec addr )
|
||||
{
|
||||
handle( JNICmd.CMD_RECEIVE, msg, addr );
|
||||
return this;
|
||||
}
|
||||
|
||||
public void sendChat( String chat )
|
||||
{
|
||||
handle( JNICmd.CMD_SENDCHAT, chat );
|
||||
}
|
||||
|
||||
public void handle( JNICmd cmd, Object... args )
|
||||
{
|
||||
QueueElem elem = new QueueElem( cmd, true, args );
|
||||
m_queue.add( elem );
|
||||
m_queue.add( new QueueElem( cmd, true, args ) );
|
||||
if ( m_stopped && ! JNICmd.CMD_NONE.equals(cmd) ) {
|
||||
DbgUtils.logf( "WARNING: adding %s to stopped thread!!!",
|
||||
cmd.toString() );
|
||||
|
@ -639,10 +751,59 @@ public class JNIThread extends Thread {
|
|||
return XwJNI.server_do( gamePtr );
|
||||
}
|
||||
|
||||
// public void run( boolean isUI, Runnable runnable )
|
||||
// {
|
||||
// Object[] args = { runnable };
|
||||
// QueueElem elem = new QueueElem( JNICmd.CMD_RUN, isUI, args );
|
||||
// m_queue.add( elem );
|
||||
// }
|
||||
private static Map<Long, JNIThread> s_instances = new HashMap<Long, JNIThread>();
|
||||
private void retain_sync()
|
||||
{
|
||||
++m_refCount;
|
||||
DbgUtils.logf( "JNIThread.retain_sync(rowid=%d): m_refCount: %d",
|
||||
m_rowid, m_refCount );
|
||||
}
|
||||
|
||||
public JNIThread retain()
|
||||
{
|
||||
synchronized( s_instances ) {
|
||||
retain_sync();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public void release()
|
||||
{
|
||||
boolean stop = false;
|
||||
synchronized( s_instances ) {
|
||||
if ( 0 == --m_refCount ) {
|
||||
s_instances.remove( m_rowid );
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
DbgUtils.logf( "JNIThread.release(rowid=%d): m_refCount: %d",
|
||||
m_rowid, m_refCount );
|
||||
|
||||
if ( stop ) {
|
||||
waitToStop( true );
|
||||
} else {
|
||||
handle( JNICmd.CMD_SAVE ); // in case releaser has made changes
|
||||
}
|
||||
}
|
||||
|
||||
public static JNIThread getRetained( long rowid )
|
||||
{
|
||||
return getRetained( rowid, false );
|
||||
}
|
||||
|
||||
public static JNIThread getRetained( long rowid, boolean makeNew )
|
||||
{
|
||||
JNIThread result = null;
|
||||
synchronized( s_instances ) {
|
||||
result = s_instances.get( rowid );
|
||||
if ( null == result && makeNew ) {
|
||||
result = new JNIThread( rowid );
|
||||
s_instances.put( rowid, result );
|
||||
}
|
||||
if ( null != result ) {
|
||||
result.retain_sync();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -130,7 +130,7 @@ public interface UtilCtxt {
|
|||
static final int ERR_RELAY_BASE = 17;
|
||||
void userError( int id );
|
||||
|
||||
void informMove( String expl, String words );
|
||||
void informMove( int turn, String expl, String words );
|
||||
void informUndo();
|
||||
|
||||
void informNetDict( int lang, String oldName, String newName,
|
||||
|
@ -146,7 +146,7 @@ public interface UtilCtxt {
|
|||
boolean warnIllegalWord( String dict, String[] words, int turn,
|
||||
boolean turnLost );
|
||||
|
||||
void showChat( String msg, String fromPlayer );
|
||||
void showChat( String msg, int fromIndx, String fromName );
|
||||
|
||||
boolean phoneNumbersSame( String num1, String num2 );
|
||||
}
|
||||
|
|
|
@ -254,7 +254,7 @@ public class UtilCtxtImpl implements UtilCtxt {
|
|||
subclassOverride( "userError" );
|
||||
}
|
||||
|
||||
public void informMove( String expl, String words )
|
||||
public void informMove( int turn, String expl, String words )
|
||||
{
|
||||
subclassOverride( "informMove" );
|
||||
}
|
||||
|
@ -293,7 +293,7 @@ public class UtilCtxtImpl implements UtilCtxt {
|
|||
}
|
||||
|
||||
// These need to go into some sort of chat DB, not dropped.
|
||||
public void showChat( String msg, String fromPlayer )
|
||||
public void showChat( String msg, int fromIndx, String fromName )
|
||||
{
|
||||
subclassOverride( "showChat" );
|
||||
}
|
||||
|
|
|
@ -34,18 +34,37 @@ public class XwJNI {
|
|||
|
||||
public static class GamePtr {
|
||||
private int m_ptr = 0;
|
||||
private int m_refCount = 0;
|
||||
private long m_rowid;
|
||||
|
||||
private GamePtr( int ptr ) { m_ptr = ptr; }
|
||||
private GamePtr( int ptr, long rowid ) {
|
||||
m_ptr = ptr;
|
||||
m_rowid = rowid;
|
||||
retain();
|
||||
}
|
||||
|
||||
public int ptr() { Assert.assertTrue( 0 != m_ptr ); return m_ptr; }
|
||||
|
||||
public synchronized GamePtr retain()
|
||||
{
|
||||
++m_refCount;
|
||||
DbgUtils.logdf( "GamePtr.retain(this=%H, rowid=%d): refCount now %d",
|
||||
this, m_rowid, m_refCount );
|
||||
return this;
|
||||
}
|
||||
|
||||
// Force (via an assert in finalize() below) that this is called. It's
|
||||
// better if jni stuff isn't being done on the finalizer thread
|
||||
public void release()
|
||||
public synchronized void release()
|
||||
{
|
||||
if ( 0 != m_ptr ) {
|
||||
game_dispose( this );
|
||||
m_ptr = 0;
|
||||
--m_refCount;
|
||||
DbgUtils.logdf( "GamePtr.release(this=%H, rowid=%d): refCount now %d",
|
||||
this, m_rowid, m_refCount );
|
||||
if ( 0 == m_refCount ) {
|
||||
if ( 0 != m_ptr ) {
|
||||
game_dispose( this );
|
||||
m_ptr = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,7 +153,7 @@ public class XwJNI {
|
|||
int seed = Utils.nextRandomInt();
|
||||
String tag = String.format( "%d", rowid );
|
||||
int ptr = initJNI( getJNI().m_ptr, seed, tag );
|
||||
GamePtr result = 0 == ptr ? null : new GamePtr( ptr );
|
||||
GamePtr result = 0 == ptr ? null : new GamePtr( ptr, rowid );
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -151,14 +170,14 @@ public class XwJNI {
|
|||
|
||||
public static native void game_makeNewGame( GamePtr gamePtr,
|
||||
CurGameInfo gi,
|
||||
UtilCtxt util,
|
||||
JNIUtils jniu,
|
||||
DrawCtx draw, CommonPrefs cp,
|
||||
TransportProcs procs,
|
||||
String[] dictNames,
|
||||
byte[][] dictBytes,
|
||||
String[] dictPaths,
|
||||
String langName );
|
||||
String langName,
|
||||
UtilCtxt util,
|
||||
JNIUtils jniu,
|
||||
DrawCtx draw, CommonPrefs cp,
|
||||
TransportProcs procs );
|
||||
|
||||
public static native boolean game_makeFromStream( GamePtr gamePtr,
|
||||
byte[] stream,
|
||||
|
@ -179,18 +198,18 @@ public class XwJNI {
|
|||
JNIUtils jniu, CommonPrefs cp,
|
||||
String[] dictNames, byte[][] dictBytes,
|
||||
String[] dictPaths, String langName ) {
|
||||
game_makeNewGame( gamePtr, gi, (UtilCtxt)null, jniu,
|
||||
(DrawCtx)null, cp, (TransportProcs)null,
|
||||
dictNames, dictBytes, dictPaths, langName );
|
||||
game_makeNewGame( gamePtr, gi, dictNames, dictBytes, dictPaths, langName,
|
||||
(UtilCtxt)null, jniu, (DrawCtx)null, cp,
|
||||
(TransportProcs)null );
|
||||
}
|
||||
|
||||
public static void game_makeNewGame( GamePtr gamePtr, CurGameInfo gi,
|
||||
JNIUtils jniu, CommonPrefs cp,
|
||||
TransportProcs procs,
|
||||
String[] dictNames, byte[][] dictBytes,
|
||||
String[] dictPaths, String langName ) {
|
||||
game_makeNewGame( gamePtr, gi, (UtilCtxt)null, jniu, (DrawCtx)null,
|
||||
cp, procs, dictNames, dictBytes, dictPaths, langName );
|
||||
String[] dictPaths, String langName,
|
||||
JNIUtils jniu, CommonPrefs cp,
|
||||
TransportProcs procs ) {
|
||||
game_makeNewGame( gamePtr, gi, dictNames, dictBytes, dictPaths, langName,
|
||||
(UtilCtxt)null, jniu, (DrawCtx)null, cp, procs );
|
||||
}
|
||||
|
||||
public static boolean game_makeFromStream( GamePtr gamePtr,
|
||||
|
@ -296,6 +315,7 @@ public class XwJNI {
|
|||
public static native boolean board_commitTurn( GamePtr gamePtr );
|
||||
public static native boolean board_flip( GamePtr gamePtr );
|
||||
public static native boolean board_replaceTiles( GamePtr gamePtr );
|
||||
public static native int board_getSelPlayer( GamePtr gamePtr );
|
||||
public static native boolean board_redoReplacedTiles( GamePtr gamePtr );
|
||||
public static native void board_resetEngine( GamePtr gamePtr );
|
||||
public static native boolean board_requestHint( GamePtr gamePtr,
|
||||
|
|
|
@ -35,9 +35,9 @@ public class LocActivity extends XWActivity {
|
|||
super.onCreate( savedInstanceState, m_dlgt );
|
||||
} // onCreate
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu( Menu menu )
|
||||
{
|
||||
return m_dlgt.onCreateOptionsMenu( menu );
|
||||
}
|
||||
// @Override
|
||||
// public boolean onCreateOptionsMenu( Menu menu )
|
||||
// {
|
||||
// return m_dlgt.onCreateOptionsMenu( menu );
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
|
||||
set -u -e
|
||||
|
||||
usage() {
|
||||
[ $# -ge 1 ] && echo "Error: $1"
|
||||
echo "usage: $(basename $0) [-e|-d] [-p /path/to/.apk]"
|
||||
echo "usage: $(basename $0) [-e|-d] (-p /path/to/.apk)+"
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
@ -12,8 +12,13 @@ if [ ! -e build.xml ]; then
|
|||
usage "No build.xml; please run me from the top android directory"
|
||||
fi
|
||||
|
||||
APK=./bin/XWords4-debug.apk
|
||||
APKS=''
|
||||
DEVICES=''
|
||||
DIRNAME=$(basename $(pwd))
|
||||
ADB="$(which adb)"
|
||||
MAIN=GamesListActivity
|
||||
MAIN=Main
|
||||
|
||||
case $DIRNAME in
|
||||
XWords4-dbg)
|
||||
PKG=xw4dbg
|
||||
|
@ -29,22 +34,20 @@ case $DIRNAME in
|
|||
;;
|
||||
esac
|
||||
|
||||
DEVICES=''
|
||||
|
||||
while [ $# -ge 1 ]; do
|
||||
case $1 in
|
||||
-e)
|
||||
DEV="$(adb devices | grep '^emulator' | awk '{print $1}')"
|
||||
DEV="$($ADB devices | grep '^emulator' | awk '{print $1}')"
|
||||
DEVICES="$DEVICES $DEV"
|
||||
;;
|
||||
-d)
|
||||
DEV="$(adb devices | grep -v emulator | grep 'device$' | awk '{print $1}')"
|
||||
DEV="$($ADB devices | grep -v emulator | grep 'device$' | awk '{print $1}')"
|
||||
DEVICES="$DEVICES $DEV"
|
||||
;;
|
||||
-p)
|
||||
[ $# -gt 1 ] || usage "-p requires an argument"
|
||||
shift
|
||||
APK=$1
|
||||
APKS="$APKS $1"
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
|
@ -53,22 +56,30 @@ while [ $# -ge 1 ]; do
|
|||
shift
|
||||
done
|
||||
|
||||
[ -e $APK ] || usage "$APK not found"
|
||||
if [ -z "$DEVICES" ]; then
|
||||
while read LINE; do
|
||||
if echo $LINE | grep -q "device$"; then
|
||||
DEVICE=$(echo $LINE | awk '{print $1}')
|
||||
DEVICES="$DEVICES $DEVICE"
|
||||
fi
|
||||
done <<< "$($ADB devices)"
|
||||
fi
|
||||
|
||||
if [ -n "$DEVICES" ]; then
|
||||
echo "installing this binary. Check the age..."
|
||||
ls -l $APK
|
||||
echo ""
|
||||
# If no apk specified, take the newest built
|
||||
if [ -z "$APKS" ]; then
|
||||
APKS=$(ls -t bin/*.apk | head -n 1)
|
||||
fi
|
||||
|
||||
COUNT=0
|
||||
|
||||
for DEVICE in $DEVICES; do
|
||||
echo $DEVICE
|
||||
adb -s $DEVICE install -r $APK
|
||||
adb -s $DEVICE shell am start \
|
||||
-n org.eehouse.android.${PKG}/org.eehouse.android.${PKG}.GamesListActivity
|
||||
COUNT=$((COUNT+1))
|
||||
for APK in $APKS; do
|
||||
echo "installing $APK; details:"
|
||||
ls -l $APK
|
||||
$ADB -s $DEVICE install -r $APK
|
||||
$ADB -s $DEVICE shell am start \
|
||||
-n org.eehouse.android.${PKG}/org.eehouse.android.${PKG}.${MAIN}
|
||||
done
|
||||
COUNT=$((COUNT+1))
|
||||
done
|
||||
|
||||
echo "installed into $COUNT devices/emulators"
|
||||
|
|
60
xwords4/android/scripts/adb-logcat.sh
Executable file
60
xwords4/android/scripts/adb-logcat.sh
Executable file
|
@ -0,0 +1,60 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e -u
|
||||
|
||||
SERIAL=''
|
||||
declare -a SERIALS=[]
|
||||
ADB=$(which adb)
|
||||
|
||||
usage() {
|
||||
[ $# -ge 1 ] && echo "ERROR: $1"
|
||||
echo "usage $0 # start logcat, allowing choice if more than one device available"
|
||||
exit 1
|
||||
}
|
||||
|
||||
listSerials() {
|
||||
COUNT=0
|
||||
while read LINE; do
|
||||
SERIALS[$COUNT]=$(echo $LINE | awk '{print $1}')
|
||||
COUNT=$((COUNT+1))
|
||||
done <<< "$(adb devices | grep 'device$')"
|
||||
}
|
||||
|
||||
setSerial() {
|
||||
NSERIALS=${#SERIALS[@]}
|
||||
while :; do
|
||||
echo "There are multiple devices. Please type the index (1-$NSERIALS) of the one you want"
|
||||
COUNT=0
|
||||
while read LINE; do
|
||||
echo -n "$((COUNT+1)): "
|
||||
echo ${SERIALS[$COUNT]}
|
||||
COUNT=$((COUNT+1))
|
||||
done <<< "$(adb devices | grep 'device$')"
|
||||
read TYPED
|
||||
if [ $TYPED -gt 0 -a $TYPED -le $COUNT ]; then
|
||||
SERIAL="-s ${SERIALS[$((TYPED-1))]}"
|
||||
break
|
||||
fi
|
||||
echo "$TYPED is not between 1 and $NSERIALS"
|
||||
done
|
||||
}
|
||||
|
||||
[ $# -ge 1 ] && usage "unexpected parameter: $1"
|
||||
|
||||
listSerials
|
||||
|
||||
COUNT=${#SERIALS[@]}
|
||||
echo "COUNT: $COUNT"
|
||||
case $COUNT in
|
||||
0)
|
||||
usage "no devices found"
|
||||
;;
|
||||
1)
|
||||
SERIAL="-s $SERIALS[0]"
|
||||
;;
|
||||
*)
|
||||
setSerial
|
||||
;;
|
||||
esac
|
||||
|
||||
$ADB $SERIAL logcat
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e -u
|
||||
set -e -u -x
|
||||
|
||||
# use this: adb -s 04bd25af2523aae6 shell "pm list packages" | grep org.eehouse
|
||||
|
||||
|
@ -29,7 +29,7 @@ getPackage() {
|
|||
|
||||
WD=$(pwd)
|
||||
while :; do
|
||||
if [ -e ${WD}/android/XWords4/AndroidManifest.xml -a -d ${WD}/common ]; then
|
||||
if [ -e ${WD}/AndroidManifest.xml -a -e ${WD}/build.xml ]; then
|
||||
break
|
||||
elif [ ${WD} = '/' ]; then
|
||||
usage "reached / without finding AndroidManifest.xml"
|
||||
|
@ -37,7 +37,7 @@ while :; do
|
|||
WD=$(cd $WD/.. && pwd)
|
||||
fi
|
||||
done
|
||||
WD=$(cd $WD/android/XWords4 && pwd)
|
||||
WD=$(cd $WD && pwd)
|
||||
|
||||
# find aapt
|
||||
DIR=$(dirname $(which android))
|
||||
|
|
|
@ -5,7 +5,7 @@ set -e -u
|
|||
usage () {
|
||||
echo "usage: $(basename $0) [--tag tagname | --branch branchname] [--variant variant]"
|
||||
echo " # (uses current branch as default)"
|
||||
exit 0
|
||||
exit 1
|
||||
}
|
||||
|
||||
TAG=""
|
||||
|
|
|
@ -74,13 +74,17 @@ esac
|
|||
# generate local.properties
|
||||
[ -e local.properties ] || ../scripts/setup_local_props.sh
|
||||
|
||||
ant $CMDS
|
||||
# If this fails, the "set -e" above means we won't try to install anything
|
||||
[ -n "$CMDS" ] && ant $CMDS
|
||||
|
||||
if [ -n "$UNINSTALL" ]; then
|
||||
uninstall
|
||||
fi
|
||||
|
||||
if [ -n "$INSTALL" ]; then
|
||||
adb-install.sh -e -d
|
||||
# Find the newest apk in this directory and install it
|
||||
APK=$(ls -t bin/*.apk | head -n 1)
|
||||
adb-install.sh -p $APK
|
||||
fi
|
||||
|
||||
# if [ "$CMDS" != "${CMDS%%install}" ]; then
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue