Merge branch 'android_branch' into android_translate

This commit is contained in:
Eric House 2017-01-07 13:16:55 -08:00
commit 43a68d5c07
105 changed files with 2309 additions and 1924 deletions

View file

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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
@ -6,14 +7,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="109"
android:versionCode="110"
android:versionName="@string/app_version"
>
<!-- 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="19" />
<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="23" />
<supports-screens android:resizeable="true"
android:smallScreens="true"

View file

@ -7,7 +7,7 @@
to come from a domain that you own or have control over. -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.eehouse.android.xw4"
android:versionCode="109"
android:versionCode="111"
android:versionName="@string/app_version"
>

File diff suppressed because it is too large Load diff

View file

@ -13,10 +13,11 @@
</style>
</head>
<body>
<h2>Crosswords 4.4.114 release</h2>
<h2>Crosswords 4.4.115 release</h2>
<p>This release fixes a drawing problem on Android Nougat version
only.</p>
<p>This release uses the new permissions process introduced with
Android "Marshmallow": Crosswords only asks for permissions at
the moment they're required.</p>
<div id="survey">
<p>Please <a href="https://www.surveymonkey.com/s/GX3XLHR">take
@ -26,11 +27,20 @@
<h3>New with this release</h3>
<ul>
<li>Fix (or work around) board drawing weirdness introduced with
Nougat. It showed most often when using the hint
feature.</li>
<li>Fix a couple of crashes reported via the Play Store --
thanks!</li>
<li>Request permissions when they're needed, e.g. ask to send
SMS messages when a game is being configured to communicate
using SMS</li>
<li>New two-color icon for notifications (required by the newer
Android that supports just-in-time permissions)</li>
<li>Use less battery by being smarter about how often to check
the relay for moves (This will mostly impact those
installing from F-Droid.)</li>
<li>Stop mis-identifying tablets as data-SMS-capable (only GSM
phones are)</li>
<li>Allow board &quot;squares&quot; to be wider than tall if it
fills the screen better</li>
<li>Improvements in localization for French, Catalan, Dutch,
Czech and Japanese (via Weblate)</li>
</ul>
<p>(The full changelog
@ -38,10 +48,8 @@
<h3>Next up</h3>
<ul>
<li>Support WiFi Direct (currently working sporadically)</li>
<li>Take advantage of Marshmallow's new permissions model (where
the app only asks for permission, e.g. to send SMS, when it
needs it.)
<li>Continue work to support WiFi Direct (currently working
sporadically)</li>
</ul>
<p>Please let me know

View file

@ -11,7 +11,7 @@ LOCAL_C_INCLUDES+= \
LOCAL_LDLIBS += -llog
ifeq ($(BUILD_TARGET),debug)
LOCAL_DEBUG = -DMEM_DEBUG -DDEBUG -DENABLE_LOGGING -DCOMMS_CHECKSUM -Wno-unused-but-set-variable
LOCAL_DEBUG = -DMEM_DEBUG -DDEBUG -DENABLE_LOGGING -DCOMMS_CHECKSUM -Wno-unused-variable
endif
LOCAL_DEFINES += \
$(LOCAL_DEBUG) \

View file

@ -10,6 +10,11 @@
style="@style/evenly_spaced_horizontal"
/>
<Button android:id="@+id/button_settings"
android:text="@string/bt_pair_settings"
style="@style/evenly_spaced_horizontal"
/>
<Button android:id="@+id/button_clear"
android:text="@string/bt_pick_clear_button"
style="@style/evenly_spaced_horizontal"

View file

@ -22,6 +22,7 @@
<FrameLayout android:id="@+id/frame"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
/>
</LinearLayout>

View file

@ -17,8 +17,6 @@
android:clickable="false"
/>
add_self_button
<Button android:id="@+id/button_clear"
android:text="@string/bt_pick_clear_button"
style="@style/evenly_spaced_horizontal"

View file

@ -3,8 +3,8 @@
<org.eehouse.android.xw4.TwoStrsItem
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="8dp"
android:paddingRight="8dp"
>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_version">4.4.114</string>
<string name="app_version">4.4.115</string>
</resources>

View file

@ -125,7 +125,6 @@
<string name="key_nag_intervals">key_nag_intervals</string>
<string name="key_download_path">key_download_path</string>
<string name="key_got_langdict">key_got_langdict</string>
<string name="key_notagain_missing_perms">key_notagain_missing_perms</string>
<string name="key_xlations_locale">key_xlations_locale</string>
<string name="key_xlations_enabled">key_xlations_enabled</string>
<string name="key_invite_multi">key_invite_multi</string>

View file

@ -598,7 +598,7 @@
only once per game. -->
<plurals name="msg_relay_waiting_fmt">
<item quantity="one">Device %1$d connected to relay in
room \"%2$s\". Waiting for %3$d player.</item>
room \"%2$s\". Waiting for one player.</item>
<item quantity="other">Device %1$d connected to relay in
room \"%2$s\". Waiting for %3$d players.</item>
</plurals>
@ -1750,7 +1750,7 @@
<string name="about_vers_fmt">Crosswords for Android, Version %1$s,
rev %2$s, built on %3$s.</string>
<!-- copyright info -->
<string name="about_copyright">Copyright (C) 1998-2016 by Eric
<string name="about_copyright">Copyright (C) 1998-2017 by Eric
House. This free/open source software is released under the GNU Public
License.</string>
@ -1864,6 +1864,8 @@
<string name="bt_pick_addall_button">Add all Paired</string>
<!-- -->
<string name="bt_pick_clear_button">Remove checked</string>
<!-- -->
<string name="bt_pair_settings">Pair More</string>
<!-- -->
<string name="invite_progress_title">Connecting...</string>
@ -2043,9 +2045,10 @@
<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
that your device supports.)</string>
to connect and cannot be played.\n\n(It was probably created from
an invitation that didn\'t specify any way of connecting that your
device supports, or you may have recently removed its last way of
connecting.)</string>
<!-- -->
<string name="connstat_net_fmt">Network status for game connected via
%1$s:</string>
@ -2437,9 +2440,9 @@
<string name="lmi_tiles_fmt">Tiles assigned to %1$s</string>
<string name="bt_no_devs">You currently have no paired Bluetooth
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>
devices (or Bluetooth is turned off). 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 via Bluetooth
to Crosswords on the device %1$s. Please check that the device is
within Bluetooth range and that Crosswords is installed on
@ -2717,26 +2720,73 @@
<string name="after_restart">This change will not take effect until
you restart Crosswords.</string>
<string name="not_again_missing_perms">This game is configured to
<string name="missing_perms">This game is configured to
communicate via SMS but Crosswords does not have permission to do
so. You can still open the game, but it may not be able to send or
receive moves.\n\nYou can re-open it to be asked for permission
again. Or you can remove the SMS communication setting.</string>
<string name="phone_state_rationale">Crosswords wants to determine
whether your phone can send SMS \"data\" messages to give you the
option of playing that way. If you don\'t ever want to play via SMS,
e.g. because you pay for each message or have a Verizon phone, it\'s
safe to permanently deny permission.
<string name="download_rationale">Crosswords needs access to
temporary storage to keep what you\'re about to download.
</string>
<string name="contacts_rationale">Crosswords want access to your
contacts in order to put a name to phone numbers that send you
invitations via SMS. You\'ll still be able to receive invitations if
you don\'t grant this permission, but only the phone number of the
sender will be displayed.</string>
<string name="sms_invite_rationale">
Crosswords needs permission to send an invitation via SMS.
</string>
<string name="dicts_storage_rationale">
Crosswords can store and read wordlists in your device\'s
Downloads area but it needs permission to access them
there.\n\nYou can safely deny this permission if you will never
download wordlists except from inside Crosswords and have not
previously stored any there.
</string>
<string name="phone_state_rationale">
Some phones can exchange SMS \"data\" messages. Crosswords would
like to offer you this option but needs to ask your device about
itself first (to learn if it\'s a phone and if so what
type.)\n\nIf your device can\'t send data SMS (e.g. because it
isn\'t a phone) or you don\'t ever want to play via SMS
(e.g. because you pay for each message), it\'s safe to permanently
deny permission.
</string>
<string name="phone_lookup_rationale">
To rematch a game that uses SMS Crosswords needs permission to
access your phone number.
</string>
<!-- Case where SMS is the only way the game can communicate -->
<string name="phone_lookup_rationale_drop">Rematching this SMS-only
game is not possible without this permission.</string>
<!-- Case where SMS is NOT the only way the game can communicate -->
<string name="phone_lookup_rationale_others">Without this permission
rematching will continue but will create a game that cannot not play
via SMS.</string>
<string name="contacts_rationale">
Crosswords want access to your contacts in order to put a name to
phone numbers that send you invitations via SMS. You\'ll still be
able to receive invitations if you don\'t grant this permission,
but only the phone number of the sender will be displayed.
</string>
<string name="move_dict_rationale">Storing a wordlist in the
Downloads area requires permission.</string>
<string name="remove_sms">Remove SMS</string>
<!-- In the permissions rationale explanation, means go ahead and
have the OS ask for permission -->
<string name="button_ask_again">Ask again</string>
<string name="contact_not_found">Not in Contacts</string>
<!-- Displayed as a toast -->
<string name="sms_send_failed">SMS send failed</string>
<!-- In the permissions rationale explanation, means don't have the
OS ask for permission: user is denying it implicitly -->
<string name="button_skip">Skip</string>
<string name="perms_rationale_title">Android Permissions</string>
<string name="toast_no_permission">Permission not granted</string>
</resources>

View file

@ -511,7 +511,7 @@
only once per game. -->
<plurals name="msg_relay_waiting_fmt">
<item quantity="one">Ecived %1$d detcennoc ot yaler ni
moor \"%2$s\". Gnitiaw rof %3$d reyalp.</item>
moor \"%2$s\". Gnitiaw rof eno reyalp.</item>
<item quantity="other">Ecived %1$d detcennoc ot yaler ni
moor \"%2$s\". Gnitiaw rof %3$d sreyalp.</item>
</plurals>
@ -1508,7 +1508,7 @@
<string name="about_vers_fmt">Sdrowssorc rof ,diordna Noisrev %1$s,
ver %2$s, tliub no %3$s.</string>
<!-- copyright info -->
<string name="about_copyright">Thgirypoc )C( 6102-8991 yb Cire
<string name="about_copyright">Thgirypoc )C( 7102-8991 yb Cire
Esuoh. Siht nepo/eerf ecruos erawtfos si desaeler rednu eht UNG Cilbup
Esnecil.</string>
<!-- Another paragraph in the about dialog -->
@ -1607,6 +1607,8 @@
<!-- -->
<string name="bt_pick_clear_button">Evomer dekcehc</string>
<!-- -->
<string name="bt_pair_settings">Riap Erom</string>
<!-- -->
<string name="invite_progress_title">Gnitcennoc...</string>
<string name="invite_progress_fmt">Gnidnes noitativni ot Sdrowssorc no %1$s</string>
<!-- -->
@ -1764,9 +1766,10 @@
<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
taht ruoy ecived stroppus.)</string>
ot tcennoc dna tonnac eb deyalp.\n\ntI( saw ylbaborp detaerc morf
na noitativni taht ndid\'t yficeps yna yaw fo gnitcennoc taht ruoy
ecived ,stroppus ro uoy yam evah yltnecer devomer sti tsal yaw fo
gnitcennoc.)</string>
<!-- -->
<string name="connstat_net_fmt">Krowten sutats rof emag detcennoc aiv
%1$s:</string>
@ -2093,9 +2096,9 @@
<string name="lmi_phony_fmt">%1$s tsol a nrut</string>
<string name="lmi_tiles_fmt">Selit dengissa ot %1$s</string>
<string name="bt_no_devs">Uoy yltnerruc evah on deriap Htooteulb
secived. Dluow uoy ekil ot nepo eht Diordna Sgnittes Lenap ot dda
eno ro ?erom\n\nuOy( yam osla deen ot nepo ti no eht ecived uoy
tnaw ot riap htiw.)</string>
secived ro( Htooteulb si denrut )ffo. Dluow uoy ekil ot nepo eht
Diordna Sgnittes Lenap ot dda eno ro ?erom\n\nuOy( yam osla deen
ot nepo ti no eht ecived uoy tnaw ot riap htiw.)</string>
<string name="app_not_found_fmt">Elbanu ot tcennoc aiv Htooteulb
ot Sdrowssorc no eht ecived %1$s. Esaelp kcehc taht eht ecived si
nihtiw Htooteulb egnar dna taht Sdrowssorc si dellatsni no
@ -2319,22 +2322,62 @@
<string name="dualpane_restart">Gnitixe ppa…</string>
<string name="after_restart">Siht egnahc lliw ton ekat tceffe litnu
uoy tratser Sdrowssorc.</string>
<string name="not_again_missing_perms">Siht emag si derugifnoc ot
<string name="missing_perms">Siht emag si derugifnoc ot
etacinummoc aiv SMS tub Sdrowssorc seod ton evah noissimrep ot od
os. Uoy nac llits nepo eht ,emag tub ti yam ton eb elba ot dnes ro
eviecer sevom.\n\nUoy nac nepo-er ti ot eb deksa rof noissimrep
niaga. Ro uoy nac evomer eht SMS noitacinummoc gnittes.</string>
<string name="phone_state_rationale">Sdrowssorc stnaw ot enimreted
rehtehw ruoy enohp nac dnes SMS \"atad\" segassem ot evig uoy eht
noitpo fo gniyalp taht yaw. Fi uoy nod\'t reve tnaw ot yalp aiv ,SMs
e.g. esuaceb uoy yap rof hcae egassem ro evah a Nozirev ,enohp ti\'s
efas ot yltnenamrep yned noissimrep.
<string name="download_rationale">Sdrowssorc sdeen ssecca ot
yraropmet egarots ot peek tahw uoy\'er tuoba ot daolnwod.
</string>
<string name="contacts_rationale">Sdrowssorc tnaw ssecca ot ruoy
stcatnoc ni redro ot tup a eman ot enohp srebmun taht dnes uoy
snoitativni aiv SMS. Uoy\'ll llits eb elba ot eviecer snoitativni fi
uoy nod\'t tnarg siht ,noissimrep tub ylno eht enohp rebmun fo eht
rednes lliw eb deyalpsid.</string>
<string name="sms_invite_rationale">
Sdrowssorc sdeen noissimrep ot dnes na noitativni aiv SMS.
</string>
<string name="dicts_storage_rationale">
Sdrowssorc nac erots dna daer stsildrow ni ruoy ecived\'s
Sdaolnwod aera tub ti sdeen noissimrep ot ssecca meht
ereht.\n\nUoy nac ylefas yned siht noissimrep fi uoy lliw reven
daolnwod stsildrow tpecxe morf edisni Sdrowssorc dna evah ton
ylsuoiverp derots yna ereht.
</string>
<string name="phone_state_rationale">
Emos senohp nac egnahcxe SMS \"atad\" segassem. Sdrowssorc dluow
ekil ot reffo uoy siht noitpo tub sdeen ot ksa ruoy ecived tuoba
flesti tsrif ot( nrael fi ti\'s a enohp dna fi os tahw
epyt.)\n\nFi ruoy ecived nac\'t dnes atad SMS e(.g. esuaceb ti
nsi\'t a )enohp ro uoy nod\'t reve tnaw ot yalp aiv SMS
e(.g. esuaceb uoy yap rof hcae ,)egassem ti\'s efas ot yltnenamrep
yned noissimrep.
</string>
<string name="phone_lookup_rationale">
Ot hctamer a emag taht sesu SMS Sdrowssorc sdeen noissimrep ot
ssecca ruoy enohp rebmun.
</string>
<!-- Case where SMS is the only way the game can communicate -->
<string name="phone_lookup_rationale_drop">Gnihctamer siht YLNo-sms
emag si ton elbissop tuohtiw siht noissimrep.</string>
<!-- Case where SMS is NOT the only way the game can communicate -->
<string name="phone_lookup_rationale_others">Tuohtiw siht noissimrep
gnihctamer lliw eunitnoc tub lliw etaerc a emag taht tonnac ton yalp
aiv SMS.</string>
<string name="contacts_rationale">
Sdrowssorc tnaw ssecca ot ruoy stcatnoc ni redro ot tup a eman ot
enohp srebmun taht dnes uoy snoitativni aiv SMS. Uoy\'ll llits eb
elba ot eviecer snoitativni fi uoy nod\'t tnarg siht ,noissimrep
tub ylno eht enohp rebmun fo eht rednes lliw eb deyalpsid.
</string>
<string name="move_dict_rationale">Gnirots a tsildrow ni eht
Sdaolnwod aera seriuqer noissimrep.</string>
<string name="remove_sms">Evomer SMS</string>
<!-- In the permissions rationale explanation, means go ahead and
have the OS ask for permission -->
<string name="button_ask_again">Ksa niaga</string>
<string name="contact_not_found">Ton ni Stcatnoc</string>
<!-- Displayed as a toast -->
<string name="sms_send_failed">SMS dnes deliaf</string>
<!-- In the permissions rationale explanation, means don't have the
OS ask for permission: user is denying it implicitly -->
<string name="button_skip">Piks</string>
<string name="perms_rationale_title">Diordna Snoissimrep</string>
<string name="toast_no_permission">Noissimrep ton detnarg</string>
</resources>

View file

@ -48,7 +48,9 @@
<string name="board_menu_game_resend">Reenvia els missatges</string>
<string name="board_menu_file_about">Quant al Crosswords…</string>
<!-- returned by util_getUserString -->
<string name="strd_robot_traded_fmt">El robot ha canviat %1$d fitxes en aquest torn.</string>
<plurals name="strd_robot_traded_fmt">
<item quantity="other">El robot ha canviat %1$d fitxes en aquest torn.</item>>
</plurals>
<!--string name="str_robot_moved">El robot ha fet aquesta jugada:</string-->
<string name="strs_values_header_fmt">%1$s quantitat/valors:\n</string>
<string name="strd_remaining_tiles_add_fmt">+ %1$d [fitxes romanents]</string>
@ -144,7 +146,6 @@
<string name="tile_back">Fons de la fitxa</string>
<string name="empty">Cel·la buida/fons</string>
<string name="clr_crosshairs">Creu d\'ubicació</string>
<string name="msg_relay_waiting_fmt">Esteu connectat al repetidor. S\'està esperant a %1$d jugador/s.</string>
<string name="relay_alert">Error en la connexió</string>
<string name="msg_too_many">Esteu proveint més jugadors dels que espera l\'amfitrió.</string>
<string name="msg_no_room">Cap amfitrió no ha registrat una sala amb aquest nom.</string>
@ -843,10 +844,6 @@ que connecti via el repetidor.</string>
<string name="warn_nomobile_fmt">El número %1$s de %2$s no sembla un número de mòbil. Voleu importar-lo igualment?</string>
<string name="get_sms_number">Introduïu el número de telèfon:</string>
<plurals name="confirm_clear_fmt">
<item quantity="one">Esteu segur de voler suprimir el número de telèfon seleccionat?</item>
<item quantity="other">Esteu segur de voler suprimir els %1$d números de telèfon seleccionats?</item>
</plurals>
<string name="connect_label_sms">Connexió (via SMS/missatges)</string>
<string name="phone_label">Números connectats:</string>
<string name="summary_conn_sms_fmt">Partida en joc amb %1$s</string>
@ -939,11 +936,6 @@ que connecti via el repetidor.</string>
<string name="force_tablet_title">Força la disposició de tauleta</string>
<string name="force_tablet_summary">Encara que la pantalla sigui massa petita</string>
<plurals name="resend_finished_fmt">
<item quantity="one">Reenviament finalitzat, s\'ha enviat %1$d missatge.</item>
<item quantity="other">Reenviament finalitzat, s\'han enviat %1$d missatges.</item>
</plurals>
<string name="dup_game_query_fmt">Ja teniu una partida que sembla s\'ha creat (el %1$s) amb la mateixa invitació. Esteu segur de voler crear-ne una altra?</string>
<string name="not_again_sync">Aquesta acció comprova que no hi hagin jugades o missatges pendents al repetidor de totes partides i marca aquelles amb jugades pendents. Si obriu una partida marcada connectarà i sincronitzarà. (en una versió posterior aquestes jugades es baixaran en segon pla.)</string>

View file

@ -511,7 +511,7 @@
only once per game. -->
<plurals name="msg_relay_waiting_fmt">
<item quantity="one">DEVICE %1$d CONNECTED TO RELAY IN
ROOM \"%2$s\". WAITING FOR %3$d PLAYER.</item>
ROOM \"%2$s\". WAITING FOR ONE PLAYER.</item>
<item quantity="other">DEVICE %1$d CONNECTED TO RELAY IN
ROOM \"%2$s\". WAITING FOR %3$d PLAYERS.</item>
</plurals>
@ -1508,7 +1508,7 @@
<string name="about_vers_fmt">CROSSWORDS FOR ANDROID, VERSION %1$s,
REV %2$s, BUILT ON %3$s.</string>
<!-- copyright info -->
<string name="about_copyright">COPYRIGHT (C) 1998-2016 BY ERIC
<string name="about_copyright">COPYRIGHT (C) 1998-2017 BY ERIC
HOUSE. THIS FREE/OPEN SOURCE SOFTWARE IS RELEASED UNDER THE GNU PUBLIC
LICENSE.</string>
<!-- Another paragraph in the about dialog -->
@ -1607,6 +1607,8 @@
<!-- -->
<string name="bt_pick_clear_button">REMOVE CHECKED</string>
<!-- -->
<string name="bt_pair_settings">PAIR MORE</string>
<!-- -->
<string name="invite_progress_title">CONNECTING...</string>
<string name="invite_progress_fmt">SENDING INVITATION TO CROSSWORDS ON %1$s</string>
<!-- -->
@ -1764,9 +1766,10 @@
<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
THAT YOUR DEVICE SUPPORTS.)</string>
TO CONNECT AND CANNOT BE PLAYED.\n\n(IT WAS PROBABLY CREATED FROM
AN INVITATION THAT DIDN\'T SPECIFY ANY WAY OF CONNECTING THAT YOUR
DEVICE SUPPORTS, OR YOU MAY HAVE RECENTLY REMOVED ITS LAST WAY OF
CONNECTING.)</string>
<!-- -->
<string name="connstat_net_fmt">NETWORK STATUS FOR GAME CONNECTED VIA
%1$s:</string>
@ -2093,9 +2096,9 @@
<string name="lmi_phony_fmt">%1$s LOST A TURN</string>
<string name="lmi_tiles_fmt">TILES ASSIGNED TO %1$s</string>
<string name="bt_no_devs">YOU CURRENTLY HAVE NO PAIRED BLUETOOTH
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>
DEVICES (OR BLUETOOTH IS TURNED OFF). 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 VIA BLUETOOTH
TO CROSSWORDS ON THE DEVICE %1$s. PLEASE CHECK THAT THE DEVICE IS
WITHIN BLUETOOTH RANGE AND THAT CROSSWORDS IS INSTALLED ON
@ -2319,22 +2322,62 @@
<string name="dualpane_restart">EXITING APP…</string>
<string name="after_restart">THIS CHANGE WILL NOT TAKE EFFECT UNTIL
YOU RESTART CROSSWORDS.</string>
<string name="not_again_missing_perms">THIS GAME IS CONFIGURED TO
<string name="missing_perms">THIS GAME IS CONFIGURED TO
COMMUNICATE VIA SMS BUT CROSSWORDS DOES NOT HAVE PERMISSION TO DO
SO. YOU CAN STILL OPEN THE GAME, BUT IT MAY NOT BE ABLE TO SEND OR
RECEIVE MOVES.\n\nYOU CAN RE-OPEN IT TO BE ASKED FOR PERMISSION
AGAIN. OR YOU CAN REMOVE THE SMS COMMUNICATION SETTING.</string>
<string name="phone_state_rationale">CROSSWORDS WANTS TO DETERMINE
WHETHER YOUR PHONE CAN SEND SMS \"DATA\" MESSAGES TO GIVE YOU THE
OPTION OF PLAYING THAT WAY. IF YOU DON\'T EVER WANT TO PLAY VIA SMS,
E.G. BECAUSE YOU PAY FOR EACH MESSAGE OR HAVE A VERIZON PHONE, IT\'S
SAFE TO PERMANENTLY DENY PERMISSION.
<string name="download_rationale">CROSSWORDS NEEDS ACCESS TO
TEMPORARY STORAGE TO KEEP WHAT YOU\'RE ABOUT TO DOWNLOAD.
</string>
<string name="contacts_rationale">CROSSWORDS WANT ACCESS TO YOUR
CONTACTS IN ORDER TO PUT A NAME TO PHONE NUMBERS THAT SEND YOU
INVITATIONS VIA SMS. YOU\'LL STILL BE ABLE TO RECEIVE INVITATIONS IF
YOU DON\'T GRANT THIS PERMISSION, BUT ONLY THE PHONE NUMBER OF THE
SENDER WILL BE DISPLAYED.</string>
<string name="sms_invite_rationale">
CROSSWORDS NEEDS PERMISSION TO SEND AN INVITATION VIA SMS.
</string>
<string name="dicts_storage_rationale">
CROSSWORDS CAN STORE AND READ WORDLISTS IN YOUR DEVICE\'S
DOWNLOADS AREA BUT IT NEEDS PERMISSION TO ACCESS THEM
THERE.\n\nYOU CAN SAFELY DENY THIS PERMISSION IF YOU WILL NEVER
DOWNLOAD WORDLISTS EXCEPT FROM INSIDE CROSSWORDS AND HAVE NOT
PREVIOUSLY STORED ANY THERE.
</string>
<string name="phone_state_rationale">
SOME PHONES CAN EXCHANGE SMS \"DATA\" MESSAGES. CROSSWORDS WOULD
LIKE TO OFFER YOU THIS OPTION BUT NEEDS TO ASK YOUR DEVICE ABOUT
ITSELF FIRST (TO LEARN IF IT\'S A PHONE AND IF SO WHAT
TYPE.)\n\nIF YOUR DEVICE CAN\'T SEND DATA SMS (E.G. BECAUSE IT
ISN\'T A PHONE) OR YOU DON\'T EVER WANT TO PLAY VIA SMS
(E.G. BECAUSE YOU PAY FOR EACH MESSAGE), IT\'S SAFE TO PERMANENTLY
DENY PERMISSION.
</string>
<string name="phone_lookup_rationale">
TO REMATCH A GAME THAT USES SMS CROSSWORDS NEEDS PERMISSION TO
ACCESS YOUR PHONE NUMBER.
</string>
<!-- Case where SMS is the only way the game can communicate -->
<string name="phone_lookup_rationale_drop">REMATCHING THIS SMS-ONLY
GAME IS NOT POSSIBLE WITHOUT THIS PERMISSION.</string>
<!-- Case where SMS is NOT the only way the game can communicate -->
<string name="phone_lookup_rationale_others">WITHOUT THIS PERMISSION
REMATCHING WILL CONTINUE BUT WILL CREATE A GAME THAT CANNOT NOT PLAY
VIA SMS.</string>
<string name="contacts_rationale">
CROSSWORDS WANT ACCESS TO YOUR CONTACTS IN ORDER TO PUT A NAME TO
PHONE NUMBERS THAT SEND YOU INVITATIONS VIA SMS. YOU\'LL STILL BE
ABLE TO RECEIVE INVITATIONS IF YOU DON\'T GRANT THIS PERMISSION,
BUT ONLY THE PHONE NUMBER OF THE SENDER WILL BE DISPLAYED.
</string>
<string name="move_dict_rationale">STORING A WORDLIST IN THE
DOWNLOADS AREA REQUIRES PERMISSION.</string>
<string name="remove_sms">REMOVE SMS</string>
<!-- In the permissions rationale explanation, means go ahead and
have the OS ask for permission -->
<string name="button_ask_again">ASK AGAIN</string>
<string name="contact_not_found">NOT IN CONTACTS</string>
<!-- Displayed as a toast -->
<string name="sms_send_failed">SMS SEND FAILED</string>
<!-- In the permissions rationale explanation, means don't have the
OS ask for permission: user is denying it implicitly -->
<string name="button_skip">SKIP</string>
<string name="perms_rationale_title">ANDROID PERMISSIONS</string>
<string name="toast_no_permission">PERMISSION NOT GRANTED</string>
</resources>

View file

@ -47,7 +47,6 @@
<string name="board_menu_game_resend">Přeposlat zprávy</string>
<string name="board_menu_file_about">O Crosswords</string>
<!-- returned by util_getUserString -->
<string name="strd_robot_traded_fmt">Robot v tomto tahu vyměnil %1$d kamenů.</string>
<!--string name="str_robot_moved">Robot provedl tento tah:</string-->
<string name="strs_values_header_fmt">%1$s počet/hodnota:\n</string>
<string name="strd_remaining_tiles_add_fmt">+ %1$d [všechny zbývající kameny]</string>
@ -61,7 +60,6 @@
<string name="strd_cumulative_score_fmt">Souhrnné skóre: %1$d</string>
<string name="strs_new_tiles_fmt">Nové kameny: %1$s</string>
<string name="str_passed">Prošel</string>
<string name="strsd_summaryscored_fmt">%1$s:%2$d</string>
<string name="str_lostturn">Tah byl ztracen</string>
<string name="str_commit_confirm">Potvrdit tento tah?\n</string>
<string name="str_bonus_all">Bonus za využití všech kamenů: 50\n</string>
@ -129,7 +127,6 @@
<string name="bonus_w3x">Trojitá hodnota slova</string>
<string name="tile_back">Pozadí kamenů</string>
<string name="empty">Prázdné pole/pozadí</string>
<string name="msg_relay_waiting_fmt">Připojen na relay. Čekám na %1$d hráče.</string>
<string name="relay_alert">Chyba připojení</string>
<string name="msg_too_many">Chcete přihlásit více hráčů než očekává server.</string>
<string name="msg_no_room">Žádný server si nezaregistroval místnost s tímto jménem.</string>

View file

@ -123,10 +123,10 @@ Diese Aktion kann nicht rückgängig gemacht werden.</item>
<string name="no_games_to_refresh">Keine Spiele gefunden, die über die Zwischenstation verbunden sind.</string>
<string name="no_copy_network">Spiele, die bereits über die Zwischenstation verbunden sind, können nicht kopiert werden. Wählen Sie „Neu aus“, um eine spielbereite Kopie mit den komplett gleichen Einstellungen zu bekommen.</string>
<string name="invit_expl_relay_fmt">Die Einladung wurde von der Zwischenstation zu einem anderen Gerät auf %s weitergeleitet</string>
<string name="invit_expl_relay_fmt">Die Einladung wurde von der Zwischenstation zu einem anderen Gerät auf %1$s weitergeleitet</string>
<plurals name="msg_relay_waiting_fmt">
<item quantity="one">Gerät %d verbunden mit Zwischenstation in Raum „%s“. Warten auf einen Spieler.</item>
<item quantity="other">Gerät %d verbunden mit Zwischenstation in Raum „%s“. Warten auf %d Spieler.</item>
<item quantity="one">Gerät %1$d verbunden mit Zwischenstation in Raum „%2$s“. Warten auf einen Spieler.</item>
<item quantity="other">Gerät %1$d verbunden mit Zwischenstation in Raum „%2$s“. Warten auf %3$d Spieler.</item>
</plurals>
<string name="msg_lost_other">Die Zwischenstation hat den Kontakt zu einem anderen Gerät in diesem Spiel verloren.</string>
@ -139,7 +139,7 @@ Diese Aktion kann nicht rückgängig gemacht werden.</item>
<string name="list_item_new_from">Kopie anlegen</string>
<plurals name="confirm_reset_fmt">
<item quantity="one">Möchten Sie das ausgewählte Spiel wirklich zurücksetzen?\n\n(Dabei gehen alle Züge und alle Verbindungsinformationen verloren.)</item>
<item quantity="other">Möchten Sie die %d ausgewählten Spiele wirklich zurücksetzen?\n\n(Dabei gehen alle Züge und alle Verbindungsinformationen verloren.)</item>
<item quantity="other">Möchten Sie die %1$d ausgewählten Spiele wirklich zurücksetzen?\n\n(Dabei gehen alle Züge und alle Verbindungsinformationen verloren.)</item>
</plurals>
</resources>

View file

@ -2539,7 +2539,7 @@ utilisez des versions différentes de la liste de mots %1$s.</string>
%1$s but the game host is using %2$s. Would you like to use %3$s
too?</string>-->
<string name="inform_dict_diffdict_fmt">Vous utilisez la liste de mots %1$s
mais l\'hôte de la partie utilise %2$s. Voulez-vous utiliser %2$s également ?</string>
mais l\'hôte de la partie utilise %2$s. Voulez-vous utiliser %3$s également ?</string>
<!--<string name="inform_dict_download">\u0020(You will have to download it
first.)</string>-->
<string name="inform_dict_download">\u0020(Vous devrez d\'abord la
@ -2900,7 +2900,7 @@ versions de %1$s maintenant ?</string>
<!--<string name="dict_info_fmt">Number of words: %1$d\nDownload size:
%2$dK\nNote: %3$s</string>-->
<string name="dict_info_fmt">Nombre de mots : %1$d\nTaille du
téléchargement : %2$dk\nNote : %2$s</string>
téléchargement : %2$dk\nNote : %3$s</string>
<!--<string name="note_none">(None)</string>-->
<string name="note_none">(aucune)</string>
<!--<string name="dict_on_server">Tap to download</string>-->

View file

@ -24,8 +24,7 @@
<string name="gamel_menu_checkmoves">移動のチェック</string>
<plurals name="moves_fmt">
<item quantity="one">%1$d 移動をプレイしました</item>
<item quantity="other"/>
<item quantity="other">%1$d 移動をプレイしました</item>
</plurals>
<string name="msgs_progress">リレーの動きなどをチェック中…</string>
@ -50,13 +49,11 @@
<string name="rename_label_caveat">(このデバイス上でのみ) このゲームの名前を変更します:</string>
<plurals name="confirm_seldeletes_fmt">
<item quantity="one">選択したゲーム %1$d を削除してもよろしいですか? この操作は元に戻せません。</item>
<item quantity="other"/>
<item quantity="other">選択したゲーム %1$d を削除してもよろしいですか? この操作は元に戻せません。</item>
</plurals>
<plurals name="confirm_reset_fmt">
<item quantity="one">選択したゲーム %1$d をリセットしますか?\n\n(リセットすると、すべての動きと接続情報を消去します。)</item>
<item quantity="other"/>
<item quantity="other">選択したゲーム %1$d をリセットしますか?\n\n(リセットすると、すべての動きと接続情報を消去します。)</item>
</plurals>
<string name="title_dicts_list">クロスワードの単語リスト</string>
@ -72,8 +69,7 @@
<string name="dicts_item_select">デフォルトにする</string>
<plurals name="confirm_delete_dict_fmt">
<item quantity="one">単語リスト %1$s を削除してもよろしいですか?</item>
<item quantity="other"/>
<item quantity="other">単語リスト %1$s を削除してもよろしいですか?</item>
</plurals>
<string name="confirm_deleteonly_dicts_fmt">%1$s を削除すると、%2$s 単語リストを除き残りません。1 つまたは複数のゲームが開けなくなります。(代わりのリストをダウンロードするまで)</string>
@ -187,8 +183,7 @@
<string name="no_moves_made">(まだ動きはありません)</string>
<plurals name="invite_msg_fmt">
<item quantity="one">このゲームは %1$d リモート プレイヤーを待っています。まだであれば - 参加するユーザーを招待しますか?</item>
<item quantity="other"/>
<item quantity="other">このゲームは %1$d リモート プレイヤーを待っています。まだであれば - 参加するユーザーを招待しますか?</item>
</plurals>
<string name="invite_if_nfc">またはタップして招待します -- 他のデバイスにも Android ビームがあり、近くにいる場合。</string>
@ -242,14 +237,12 @@
<string name="board_menu_game_resend">移動を再送信</string>
<plurals name="resend_finished_fmt">
<item quantity="one">再送信が終了しました。%1$d メッセージを送信しました。</item>
<item quantity="other"/>
<item quantity="other">再送信が終了しました。%1$d メッセージを送信しました。</item>
</plurals>
<string name="str_robot_moved_fmt">"ロボット %1$s がこの移動を行いました: "</string>
<plurals name="strd_robot_traded_fmt">
<item quantity="one">タイルを 1 つ交換しました。</item>
<item quantity="other"/>
<item quantity="other">タイルを %1$d つ交換しました。</item>
</plurals>
<string name="strs_values_header_fmt">%1$s カウント/値:\n</string>
<string name="strd_remaining_tiles_add_fmt">+ %1$d [すべての残りのタイル]</string>
@ -275,8 +268,7 @@
<item quantity="other">%1$d のタイルがプールに残っています。</item>
</plurals>
<plurals name="strd_remains_expl_fmt">
<item quantity="one">%1$d のタイルがプールとすべてのトレイに残っています:\n</item>
<item quantity="other"/>
<item quantity="other">%1$d のタイルがプールとすべてのトレイに残っています:\n</item>
</plurals>
<string name="confirm_undo_last">最後に反映した順番を元に戻してもよろしいですか? (やり直しのオプションはありません)</string>
@ -442,7 +434,7 @@
<plurals name="query_trade_fmt">
<item quantity="one">選択したタイル (%2$s) を交換してもよろしいですか?</item>
<item quantity="other"/>
<item quantity="other">選択した%1$dつのタイル (%2$s) を交換してもよろしいですか?</item>
</plurals>
<string name="chat_title_fmt">%1$s のチャット</string>
@ -655,7 +647,8 @@
<string name="new_btmove_title">Bluetooth 経由で招待</string>
<string name="new_move_body">1 つ以上の移動が届きました</string>
<plurals name="invite_bt_desc_fmt">
<item quantity="other">このゲームに追加するデバイスを選択してください。期待したデバイスが表示されない場合は、\"%2$s\" ボタンを使用してください。</item>
<item quantity="one">このゲームに追加するデバイスを選択してください。期待したデバイスが表示されない場合は、\"%2$s\" ボタンを使用してください。</item>
<item quantity="other">このゲームに追加する%1$dつのデバイスを選択してください。期待したデバイスが表示されない場合は、\"%2$s\" ボタンを使用してください。</item>
</plurals>
<string name="bt_resend_fmt">%1$s への Bluetooth 送信に失敗しました。 %2$d 秒で再試行します。</string>
<string name="bt_fail_fmt">%1$s への Bluetooth 送信に何度も失敗しています。もう一度やり直すにはゲームを再度開いてください。</string>
@ -675,15 +668,14 @@
<string name="button_sms_add">連絡先をインポート</string>
<plurals name="invite_sms_desc_fmt">
<item quantity="one">新しいゲームに招待する電話番号を確認して、\"%2$s\" をタップしてください。</item>
<item quantity="other"/>
<item quantity="other">新しいゲームに招待する%1$dつの電話番号を確認して、\"%2$s\" をタップしてください。</item>
</plurals>
<string name="manual_owner_name">(連絡先になし)</string>
<string name="warn_nomobile_fmt">%2$s の番号 %1$s は \"携帯\" 番号ではありません。インポートしますか?</string>
<string name="empty_sms_inviter">この電話番号のリストは空です。招待する人を追加するには \"連絡先をインポート\" ボタンを使用するか、+ ボタンで直接番号を入力します。</string>
<string name="get_sms_number">電話番号を入力してください:</string>
<plurals name="confirm_clear_fmt">
<item quantity="one">チェックした電話番号を削除してもよろしいですか?</item>
<item quantity="other"/>
<item quantity="other">チェックした電話番号を削除してもよろしいですか?</item>
</plurals>
<string name="connect_label_sms">接続 (SMS/テキスト経由)</string>
<string name="phone_label">接続数:</string>
@ -789,12 +781,10 @@
<string name="group_new_games">新しいゲーム</string>
<plurals name="groups_confirm_del_fmt">
<item quantity="one">選択したグループを削除してもよろしいですか?</item>
<item quantity="other"/>
<item quantity="other">選択したグループを削除してもよろしいですか?</item>
</plurals>
<plurals name="groups_confirm_del_games_fmt">
<item quantity="one">\n\n(1 つのゲームも削除されます)</item>
<item quantity="other"/>
<item quantity="other">\n\n(%1$d つのゲームも削除されます)</item>
</plurals>
<string name="rename_group_label">このグループの名前を次のように変更します:</string>
@ -803,8 +793,7 @@
<string name="cannot_delete_default_group_fmt">新しいゲームのグループ %1$s は削除できません。</string>
<plurals name="group_name_fmt">
<item quantity="one">%1$s (%2$d ゲーム)</item>
<item quantity="other"/>
<item quantity="other">%1$s (%2$d ゲーム)</item>
</plurals>
<string name="button_rematch">再戦</string>
@ -848,12 +837,11 @@
<string name="slmenu_copy_sel">クリップボードにコピー</string>
<string name="slmenu_clear_sel">選択した項目を削除</string>
<plurals name="confirm_studylist_clear_fmt">
<item quantity="one">選択した単語を削除してもよろしいですか?\n\n(この操作は元に戻すことができません。)</item>
<item quantity="other"/>
<item quantity="other">選択した単語を削除してもよろしいですか?\n\n(この操作は元に戻すことができません。)</item>
</plurals>
<plurals name="paste_done_fmt">
<item quantity="one">単語を 1 つコピーしました</item>
<item quantity="other"/>
<item quantity="other">単語を %1$d つコピーしました</item>
</plurals>
<string name="add_done_fmt">%1$s を %2$s 学習リストに追加しました</string>
<string name="studylist_title_fmt">%1$s の学習リスト</string>
@ -876,8 +864,7 @@
<string name="loc_lang_local">%1$s (あなた)</string>
<plurals name="new_xlations_fmt">
<item quantity="one">新しい翻訳を 1 つインストールしました</item>
<item quantity="other"/>
<item quantity="other">新しい翻訳を %1$d つインストールしました</item>
</plurals>
<string name="xlations_enabled_title">ローカルの翻訳を有効にする</string>
@ -934,8 +921,7 @@
<string name="note_none">(なし)</string>
<string name="dict_on_server">詳細はタップしてください</string>
<plurals name="lang_name_fmt">
<item quantity="one">%1$s (%2$d 単語リスト)</item>
<item quantity="other"/>
<item quantity="other">%1$s (%2$d 単語リスト)</item>
</plurals>
<string name="dict_desc_fmt">%1$s (%2$s/%3$d 語)</string>
@ -949,16 +935,13 @@
<string name="nag_title">リマインダー: あなたの番です</string>
<plurals name="nag_minutes_fmt">
<item quantity="one">%1$d 分</item>
<item quantity="other"/>
<item quantity="other">%1$d 分</item>
</plurals>
<plurals name="nag_hours_fmt">
<item quantity="one">%1$d 時間</item>
<item quantity="other"/>
<item quantity="other">%1$d 時間</item>
</plurals>
<plurals name="nag_days_fmt">
<item quantity="one">%1$d 日</item>
<item quantity="other"/>
<item quantity="other">%1$d 日</item>
</plurals>
<string name="nag_body_fmt">%1$s は %2$s より前に移動しました。</string>
<string name="nag_warn_last_fmt">最新の警告: %1$s</string>
@ -966,12 +949,11 @@
<string name="lmi_pass_fmt">%1$s パスしました (0 ポイント)</string>
<plurals name="lmi_move_fmt">
<item quantity="one">%1$s は %2$s プレイして %3$d ポイント</item>
<item quantity="other"/>
<item quantity="other">%1$s は %2$s プレイして %3$d ポイント</item>
</plurals>
<plurals name="lmi_trade_fmt">
<item quantity="one">%1$s はタイルを 1 つ取引しました</item>
<item quantity="other"/>
<item quantity="other">%1$s はタイルを %2$d つ取引しました</item>
</plurals>
<string name="lmi_phony_fmt">%1$s 順番を失いました</string>
<string name="lmi_tiles_fmt">タイルが %1$s に割り当てられました</string>
@ -990,8 +972,7 @@
<string name="use_defaults">デフォルトを使用する</string>
<plurals name="nplayers_fmt">
<item quantity="one">1 プレイヤー</item>
<item quantity="other"/>
<item quantity="other">%1$d つの プレイヤー</item>
</plurals>
<string name="err_dup_invite_fmt">重複した招待を拒否: デバイス \"%1$s\" は既にこのゲームへの招待を受け入れています。</string>
@ -1125,13 +1106,12 @@
<string name="button_relay_add">ゲームをスキャン</string>
<plurals name="invite_relay_desc_fmt">
<item quantity="one">あなたの新しいゲームに招待するデバイスをチェックして、\"%2$s\" をタップしてください。</item>
<item quantity="other"/>
<item quantity="other">あなたの新しいゲームに招待する%1$dのデバイスをチェックして、\"%2$s\" をタップしてください。</item>
</plurals>
<string name="empty_relay_inviter">このデバイスのリストは空です。\"ゲームをスキャン\" ボタンを使用すると、相手のあなたの古いゲームをスキャンします。デバイス ID を直接入力するには \"+\" ボタンを使用します。</string>
<string name="get_relay_number">デバイス ID を入力します:</string>
<plurals name="confirm_clear_sms_fmt">
<item quantity="one">チェックした電話番号を削除してもよろしいですか?</item>
<item quantity="other"/>
<item quantity="other">チェックした電話番号を削除してもよろしいですか?</item>
</plurals>
<string name="confirm_clear_relay">チェックしたデバイスを削除してもよろしいですか?</string>
<string name="rematch_name_fmt">再戦: %1$s</string>
@ -1158,8 +1138,7 @@
<string name="summary_invites_out">プレイヤーを招待しました</string>
<plurals name="invite_sent_fmt">
<item quantity="one">すでにこのゲームにリモート プレイヤーを招待しています。私たちは彼/彼女が対応するのを待っています。招待状が送られていないと思う場合は、再招待ボタンを使用してください。</item>
<item quantity="other"/>
<item quantity="other">すでにこのゲームにリモート プレイヤーを招待しています。私たちは彼/彼女が対応するのを待っています。招待状が送られていないと思う場合は、再招待ボタンを使用してください。</item>
</plurals>
<string name="invited_msg">このゲームは、あなたが受け取った招待状から作成されました。送信者に接続して、他の参加者が到着すると、すぐにプレイが開始されます。</string>
@ -1199,8 +1178,7 @@
<string name="warn_relay_havegames">リレーを使用したプレイを無効にしてもよろしいですか?</string>
<plurals name="warn_relay_games_fmt">
<item quantity="one">\n\n(それを使用したゲームが 1 つあります。)</item>
<item quantity="other"/>
<item quantity="other">\n\n(それを使用したゲームが %1$d つあります。)</item>
</plurals>
<string name="button_enable_relay">リレー プレイを有効にする</string>

View file

@ -13,8 +13,8 @@
<string name="summary_relay_gameover_fmt">Spel voorbij is kamer \"%1$s\"</string>
<string name="gameOver">Spel voorbij</string>
<plurals name="moves_fmt">
<item quantity="one">%1$s zet gespeeld</item>
<item quantity="other">%1$s zetten gespeeld</item>
<item quantity="one">%1$d zet gespeeld</item>
<item quantity="other">%1$d zetten gespeeld</item>
</plurals>
<string name="button_delete">Verwijder</string>
<string name="button_reset">Reset</string>
@ -813,7 +813,7 @@
<string name="button_relay_add">Scan spellen</string>
<plurals name="invite_relay_desc_fmt">
<item quantity="one">Selecteer het apparaat dat je uit wilt nodigen voor jouw nieuwe spel en druk op \"%2$s\".</item>
<item quantity="other">Selecteer de %1$s apparaten die je uit wilt nodigen voor jouw nieuwe spel en druk op \"%2$s\".</item>
<item quantity="other">Selecteer de %1$d apparaten die je uit wilt nodigen voor jouw nieuwe spel en druk op \"%2$s\".</item>
</plurals>
<string name="empty_relay_inviter">De lijst van apparaten is leeg. Gebruik de \"Scan spellen\" knop om oude spellen te doorzoeken voor tegenstanders. Gebruik de \"+\" knop om een apparaat ID direct in te voeren.</string>
<string name="get_relay_number">Voer apparaat ID in:</string>

View file

@ -20,11 +20,6 @@
<string name="list_item_copy">Kopírovať</string>
<!-- Text of confirmation dialog posted when list_item_reset menu
is selected -->
<string name="confirm_reset_fmt">XLATE ME: Are you sure you want to reset the %1$d
selected game[s]?\n\n(Resetting erases all moves and any connection
information.)</string>
<string name="confirm_seldeletes_fmt">XLATE ME: Are you sure you want to delete
the %1$d selected game[s]? This action cannot be undone.</string>
<!-- text within rename dialog (triggered by selecting
list_item_rename) -->
<string name="rename_label">XLATE ME: Change the name of this game to:</string>
@ -48,8 +43,6 @@
<!-- title for popup list of langugages from which user picks -->
<string name="title_langs_list">XLATE ME: Languages (based on installed
wordlists)</string>
<!-- -->
<string name="title_gamebt_config_fmt">XLATE ME: %1$s settings (via Bluetooth)</string>
<!-- alternate window title used when game is networked -->
<string name="title_gamenet_config_fmt">XLATE ME: %1$s settings (networked)</string>
<string name="title_prefs">Predvoľby Crosswords</string>
@ -299,7 +292,6 @@
<string name="board_menu_game_final">Celkové skóre</string>
<string name="board_menu_game_resign">XLATE ME: Resign</string>
<string name="board_menu_game_resend">Preposlať správy</string>
<string name="resend_finished_fmt">XLATE ME: Resend finished; sent %1$d message[s].</string>
<string name="board_menu_file_about">O Crosswords</string>
<!--
############################################################
@ -311,7 +303,6 @@
substituted in. -->
<string name="game_item_menu_title_fmt">XLATE ME: \"%1$s\" actions:</string>
<!-- returned by util_getUserString -->
<string name="strd_robot_traded_fmt">Robot v tomto ťahu vymenil %1$d kameňov.</string>
<!--string name="str_robot_moved">Robot uskutočnil tento ťah:</string-->
<string name="strs_values_header_fmt">%1$s počet/hodnota:\n</string>
<string name="strd_remaining_tiles_add_fmt">+ %1$d [všetky zostávajúce kamene]</string>
@ -328,10 +319,8 @@
move:\u0020</string>
<string name="strs_new_tiles_fmt">Nové kamene: %1$s</string>
<string name="str_passed">Prešiel</string>
<string name="strsd_summaryscored_fmt">%1$s:%2$d</string>
<!-- Used in formatting reports of trades (exchanges of tiles).
Number of tiles traded is substituted for %1$d-->
<string name="strd_traded_fmt">XLATE ME: Exchanged %1$d tiles</string>
<string name="str_lostturn">Ťah bol stratený</string>
<string name="str_commit_confirm">Potvrdiť tento ťah?\n</string>
<!-- Used to separate names of players when listing them on one
@ -346,12 +335,8 @@
is chosen. -->
<string name="confirm_undo_last">XLATE ME: Are you sure you want to undo the
last committed turn? (There is no redo option.)</string>
<!-- Intro to the paragraph lisiting all of the tiles remaining -->
<string name="strd_remains_expl_fmt">XLATE ME: %1$d tiles left in pool and all
tray[s]:\n</string>
<!-- First line in the remaining tiles dialog (reached by tapping
the number at left end of the scoreboard) -->
<string name="strd_remains_header_fmt">XLATE ME: %1$d tiles left in pool.</string>
<!-- error messages -->
<string name="str_tiles_not_in_line">Kamene musia ležať v jednom rade.</string>
<string name="str_no_empties_in_turn">Medzi kameňmi nesmie byť žiadne prázdne políčko.</string>
@ -408,8 +393,6 @@
the room, and how many additional players have not yet
registered with the relay in this game. This should be seen
only once per game. -->
<string name="msg_relay_waiting_fmt">XLATE ME: Device %1$d connected to relay in
room \"%2$s\". Waiting for %3$d player[s].</string>
<!-- Short for "points", this is shown at the right end of the
tray in place of the first tile placed along with the points
the current move would earn if committed. -->
@ -423,17 +406,6 @@
remote players. Be sure to address your invitation to
that many people.)</string>
<!-- If a networked game is opened and is not complete, i.e. if it
is listed as expecting remote players who have not yet shown
up, then the most likely explanation is that none has been
invited. (It's also possible that an invitation has been
sent, but I have no way of knowing that.) So every time I
open such a game I give the user a chance to issue an
invititation while trying to warn him not to send duplicates.
The number of players missing is substituted for "%1$d". -->
<string name="invite_msg_fmt">XLATE ME: This game is missing %1$d remote
player[s]. Would you like to invite someone to join -- assuming
you haven\'t already?</string>
<!-- displayed when you long-tap a scoreboard entry and there's no
most recent score to show -->
<string name="no_moves_made">XLATE ME: (No moves yet)</string>
@ -537,22 +509,10 @@
wordlist delete confiration dialog in the case where the
wordlist to be deleted is NOT the last in its language. The
name of the language is substituted for %1$s. -->
<string name="confirm_deletemore_dict_fmt">XLATE ME: \u0020One game (at least)
is using it, but there is another %1$s wordlist installed that can
replace it.</string>
<!-- Additional text appended to text confirm_delete_dictf in the
wordlist delete confiration dialog in the case where the
wordlist to be deleted is the last in its language. The name
of the language is substituted for %1$s. -->
<string name="confirm_deleteonly_dict_fmt">XLATE ME: %1$s is the only %2$s
wordlist installed. One or more games will be unopenable
without it.</string>
<!-- text of confirmation dialog posted when the delete 'X' button
beside the listing of a wordlist is tapped. The name of the
wordlist is substituted for %1$s. Sometimes one of the two
strings below is appended. -->
<string name="confirm_delete_dict_fmt">XLATE ME: Are you sure you want to
delete the wordlist[s] %1$s?</string>
<string name="settings_label">Nastavenie hry</string>
<string name="minutes_label">Minút v hre</string>
<!-- title of popup used to determine how words are handled that
@ -668,8 +628,6 @@
-->
<!-- This is the heading above the list of steps. The default
language is substituted for %1$s. -->
<string name="relay_game_explain_fmt">XLATE ME: To start a basic networked two-player
game in %1$s:</string>
<!--
############################################################
# :Menus:
@ -704,8 +662,6 @@
<string name="chat_title_fmt">XLATE ME: %1$s message history</string>
<!-- Text of dialog asking user to confirm a move that exchanges
tiles (instead of forming a new word to earn points) -->
<string name="query_trade_fmt">XLATE ME: Are you sure you want to exchange the
selected tiles (%1$s)?</string>
<string name="invite_chooser_sms">XLATE ME: sms</string>
<string name="invite_chooser_email">XLATE ME: email</string>
<!-- When I've created the invitation, in text or html, I ask
@ -1041,9 +997,6 @@
<string name="study_langpick">XLATE ME: Your words for:</string>
<string name="studylist_title_fmt">XLATE ME: Studylist for %1$s</string>
<string name="add_done_fmt">XLATE ME: %1$s added to list</string>
<string name="paste_done_fmt">XLATE ME: %1$d word[s] copied</string>
<string name="confirm_studylist_clear_fmt">XLATE ME: Are you sure you want to
delete the %1$d selected word[s]?\n\n(This action cannot be undone.)</string>
<string name="slmenu_clear_sel">XLATE ME: Delete</string>
<string name="slmenu_copy_sel">XLATE ME: Copy to clipboard</string>
<string name="gamel_menu_study">XLATE ME: Studylist…</string>
@ -1094,17 +1047,12 @@
game with the same players and parameters as the one that
just ended. -->
<string name="button_rematch">XLATE ME: Rematch</string>
<string name="group_name_fmt">XLATE ME: %1$s (%2$d games)</string>
<string name="no_move_onegroup">XLATE ME: Moving is impossible until there
is more than one group.</string>
<string name="cannot_delete_default_group_fmt">XLATE ME: The group for new games, %1$s,
cannot be deleted.</string>
<string name="game_name_group_title">XLATE ME: Name group</string>
<string name="rename_group_label">XLATE ME: Change the name of this group to:</string>
<string name="groups_confirm_del_games_fmt">XLATE ME: \n\n(%1$d game[s] will
also be deleted.)</string>
<string name="groups_confirm_del_fmt">XLATE ME: Are you sure you want to delete
the %1$d selected group[s]?</string>
<string name="group_new_games">XLATE ME: New games</string>
<string name="group_cur_games">XLATE ME: My games</string>
<string name="list_group_movedown">XLATE ME: Move down</string>
@ -1255,10 +1203,6 @@
<!-- -->
<string name="manual_owner_name">XLATE ME: (Not in contacts)</string>
<!-- -->
<string name="invite_sms_desc_fmt">XLATE ME: Please check the %1$d phone
number[s] you want to invite to your new game, then tap \"Invite
checked\".</string>
<!-- -->
<string name="button_sms_add">XLATE ME: Import contact</string>
<!-- -->
<string name="new_smsmove_title">XLATE ME: New move via SMS</string>
@ -1297,9 +1241,6 @@
<string name="bt_resend_fmt">XLATE ME: Bluetooth send to %1$s failed; retry %3$d in
%2$d seconds.</string>
<!-- -->
<string name="invite_bt_desc_fmt">XLATE ME: Please select the %1$d device[s] you
want to include in this game. Use the Rescan button if you
don\'t see a device you expect.</string>
<!-- -->
<string name="new_move_body">XLATE ME: One or more moves has arrived</string>
<!-- -->
@ -1447,7 +1388,6 @@
different (but same-language wordlist) -->
<string name="button_substdict">XLATE ME: Substitute</string>
<string name="msg_ask_password_fmt">Heslo pre \"%1$s\":</string>
<string name="notify_body_fmt">XLATE ME: Activity in game \"%1$s\"</string>
<!-- When a move is fetched from the relay a Notification is
posted. These are its title, which appears in the top bar of the
device, and the body that appears when you pull the notifications

View file

@ -23,7 +23,6 @@ package org.eehouse.android.xw4;
import android.os.Bundle;
public class BTInviteActivity extends InviteActivity {
private static final String TAG = BTInviteActivity.class.getSimpleName();
@Override
protected void onCreate( Bundle savedInstanceState )

View file

@ -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
@ -25,33 +25,23 @@ import android.app.AlertDialog;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Button;
import junit.framework.Assert;
import org.eehouse.android.xw4.DBUtils.SentInvitesInfo;
import org.eehouse.android.xw4.DlgDelegate.Action;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class BTInviteDelegate extends InviteDelegate {
private static final String TAG = BTInviteDelegate.class.getSimpleName();
private static final int[] BUTTONIDS = { R.id.button_add,
R.id.button_settings,
R.id.button_clear,
};
private Activity m_activity;
private TwoStringPair[] m_pairs;
public static void launchForResult( Activity activity, int nMissing,
SentInvitesInfo info,
@ -93,8 +83,12 @@ public class BTInviteDelegate extends InviteDelegate {
case R.id.button_add:
scan();
break;
case R.id.button_settings:
BTService.openBTSettings( m_activity );
break;
case R.id.button_clear:
Utils.notImpl( m_activity );
removeSelected();
clearChecked();
break;
}
}
@ -109,13 +103,13 @@ public class BTInviteDelegate extends InviteDelegate {
public void run() {
synchronized( BTInviteDelegate.this ) {
TwoStringPair[] pairs = null;
m_pairs = null;
if ( 0 < args.length ) {
pairs = TwoStringPair.make( (String[])(args[0]),
m_pairs = TwoStringPair.make( (String[])(args[0]),
(String[])(args[1]) );
}
updateListAdapter( pairs );
updateListAdapter( m_pairs );
tryEnable();
}
}
@ -129,18 +123,20 @@ public class BTInviteDelegate extends InviteDelegate {
@Override
protected void onChildAdded( View child, InviterItem data )
{
TwoStrsItem item = (TwoStrsItem)child; // change class name!
TwoStrsItem item = (TwoStrsItem)child;
TwoStringPair pair = (TwoStringPair)data;
((TwoStrsItem)child).setStrings( pair.str2, pair.str1 );
// null: we don't display mac address
((TwoStrsItem)child).setStrings( pair.str2, null );
}
@Override
protected void listSelected( InviterItem[] selected, String[] devs )
protected void tryEnable()
{
for ( int ii = 0; ii < selected.length; ++ii ) {
TwoStringPair rec = (TwoStringPair)selected[ii];
devs[ii] = rec.str1;
DbgUtils.logd( TAG, "selecting address %s", devs[ii] );
super.tryEnable();
Button button = (Button)findViewById( R.id.button_clear );
if ( null != button ) { // may not be there yet
button.setEnabled( 0 < getChecked().size() );
}
}
@ -158,27 +154,28 @@ public class BTInviteDelegate extends InviteDelegate {
}
// @Override
// protected void clearSelected( Integer[] itemIndices )
// {
// // String[][] selected = new String[1][];
// // listSelected( selected, null );
// // BTService.clearDevices( m_activity, selected[0] );
// // super.clearSelected( itemIndices );
// }
private void removeSelected()
{
Set<InviterItem> checked = getChecked();
String[] devs = new String[checked.size()];
Iterator<InviterItem> iter = checked.iterator();
for ( int ii = 0; iter.hasNext(); ++ii ) {
TwoStringPair pair = (TwoStringPair)iter.next();
devs[ii] = pair.str1;
}
BTService.clearDevices( m_activity, devs );
}
// DlgDelegate.DlgClickNotify interface
@Override
public void dlgButtonClicked( Action action, int which, Object[] params )
public void onPosButton( Action action, Object[] params )
{
switch( action ) {
case OPEN_BT_PREFS_ACTION:
if ( AlertDialog.BUTTON_POSITIVE == which ) {
BTService.openBTSettings( m_activity );
}
break;
default:
super.dlgButtonClicked( action, which, params );
super.onPosButton( action, params );
}
}
}

View file

@ -28,7 +28,6 @@ import android.view.Window;
import org.eehouse.android.xw4.jni.CommonPrefs;
public class BoardActivity extends XWActivity {
private static final String TAG = BoardActivity.class.getSimpleName();
private BoardDelegate m_dlgt;

View file

@ -1,7 +1,7 @@
/* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/*
* Copyright 2009 - 2016 by Eric House (xwords@eehouse.org). All
* rights reserved.
* Copyright 2009 - 2017 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
@ -54,6 +54,7 @@ import junit.framework.Assert;
import org.eehouse.android.xw4.DBUtils.SentInvitesInfo;
import org.eehouse.android.xw4.DlgDelegate.Action;
import org.eehouse.android.xw4.DlgDelegate.ActionPair;
import org.eehouse.android.xw4.Perms23.Perm;
import org.eehouse.android.xw4.Toolbar.Buttons;
import org.eehouse.android.xw4.jni.CommonPrefs;
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
@ -406,8 +407,7 @@ public class BoardDelegate extends DelegateBase
if ( self.m_summary.hasRematchInfo() ) {
self.tryRematchInvites( true );
} else {
self.callInviteChoices( Action.LAUNCH_INVITE_ACTION,
self.m_sentInfo, true );
self.callInviteChoices( self.m_sentInfo );
}
} else {
self.askDropRelay();
@ -711,6 +711,8 @@ public class BoardDelegate extends DelegateBase
// in case of change...
setBackgroundColor();
setKeepScreenOn();
} else if ( 0 < m_nMissing ) {
showDialog( DlgID.DLG_INVITE );
}
}
}
@ -720,36 +722,17 @@ public class BoardDelegate extends DelegateBase
// loop of showing the rationale over and over. Android will always tell
// us to show the rationale, but if we've done it already we need to go
// straight to asking for the permission.
private void callInviteChoices( final Action action,
final DBUtils.SentInvitesInfo info,
boolean showRationale )
private void callInviteChoices( final SentInvitesInfo info )
{
Perms23.Builder builder =
new Perms23.Builder( Perms23.Perm.READ_PHONE_STATE );
if ( showRationale ) {
builder.setOnShowRationale( new Perms23.OnShowRationale() {
@Override
public void onShouldShowRationale( Set<Perms23.Perm> perms )
{
makeOkOnlyBuilder( R.string.phone_state_rationale )
.setAction( Action.RETRY_PHONE_STATE_ACTION )
.setParams( action, info )
.show();
}
} );
Perms23.tryGetPerms( this, Perm.READ_PHONE_STATE,
R.string.phone_state_rationale,
Action.ASKED_PHONE_STATE, this, info );
}
builder.asyncQuery( m_activity, new Perms23.PermCbck() {
@Override
public void onPermissionResult( Map<Perms23.Perm,
Boolean> perms )
private void showInviteChoicesThen( Object[] params )
{
// Do the work regardless of result; just won't have
// SMS option
showInviteChoicesThen( action, info );
}
});
SentInvitesInfo info = (SentInvitesInfo)params[0];
showInviteChoicesThen( Action.LAUNCH_INVITE_ACTION, info );
}
@Override
@ -905,7 +888,7 @@ public class BoardDelegate extends DelegateBase
Action.COMMIT_ACTION )
.show();
} else {
dlgButtonClicked( Action.COMMIT_ACTION, AlertDialog.BUTTON_POSITIVE, null );
onPosButton( Action.COMMIT_ACTION, null );
}
break;
@ -1022,36 +1005,15 @@ public class BoardDelegate extends DelegateBase
//////////////////////////////////////////////////
// DlgDelegate.DlgClickNotify interface
//////////////////////////////////////////////////
@Override
public void dlgButtonClicked( Action action, int which,
final Object[] params )
{
boolean handled = false;
boolean positive = AlertDialog.BUTTON_POSITIVE == which;
DbgUtils.logd( TAG, "BoardDelegate.dlgButtonClicked(%s, %b)",
action.toString(), positive );
if ( Action.ENABLE_RELAY_DO_OR == action ) {
handled = true;
if ( positive ) {
RelayService.setEnabled( m_activity, true );
} else if ( AlertDialog.BUTTON_NEGATIVE == which ) {
m_dropOnDismiss = true;
} else if ( DlgDelegate.DISMISS_BUTTON == which && m_dropOnDismiss ) {
postDelayed( new Runnable() {
public void run() {
askDropRelay();
}
}, 10 );
}
} else if ( Action.RETRY_PHONE_STATE_ACTION == action ) {
Action stateAction = (Action)params[0];
DBUtils.SentInvitesInfo info = (DBUtils.SentInvitesInfo)params[1];
callInviteChoices( stateAction, info, false );
} else if ( positive ) {
handled = true;
@Override
public void onPosButton( Action action, final Object[] params )
{
JNICmd cmd = JNICmd.CMD_NONE;
switch ( action ) {
case ENABLE_RELAY_DO_OR:
RelayService.setEnabled( m_activity, true );
break;
case UNDO_LAST_ACTION:
cmd = JNICmd.CMD_UNDO_LAST;
break;
@ -1113,26 +1075,32 @@ public class BoardDelegate extends DelegateBase
case DROP_RELAY_ACTION:
dropConViaAndRestart(CommsConnType.COMMS_CONN_RELAY);
break;
case DROP_SMS_ACTION:
dropConViaAndRestart(CommsConnType.COMMS_CONN_SMS);
break;
case DELETE_AND_EXIT:
deleteAndClose();
break;
case DROP_SMS_ACTION: // do nothing; work done in onNegButton case
break;
case INVITE_SMS:
int nMissing = (Integer)params[0];
SentInvitesInfo info = (SentInvitesInfo)params[1];
SMSInviteDelegate.launchForResult( m_activity, nMissing, info,
RequestCode.SMS_INVITE_RESULT );
break;
case ASKED_PHONE_STATE:
showInviteChoicesThen( params );
break;
case ENABLE_SMS_DO:
handled = false; // so super gets called, before
// retrySMSInvites
post( new Runnable() {
public void run() {
retrySMSInvites( params );
}
} );
break;
// FALLTHRU: so super gets called, before
default:
handled = false;
super.onPosButton( action, params );
}
if ( JNICmd.CMD_NONE != cmd ) {
@ -1140,10 +1108,45 @@ public class BoardDelegate extends DelegateBase
}
}
if ( !handled ) {
super.dlgButtonClicked( action, which, params );
@Override
public void onNegButton( Action action, Object[] params )
{
switch ( action ) {
case ENABLE_RELAY_DO_OR:
m_dropOnDismiss = true;
break;
case DROP_SMS_ACTION:
dropConViaAndRestart(CommsConnType.COMMS_CONN_SMS);
break;
case DELETE_AND_EXIT:
finish();
break;
case ASKED_PHONE_STATE:
showInviteChoicesThen( params );
break;
default:
super.onNegButton( action, params );
}
}
@Override
public void onDismissed( Action action, Object[] params )
{
switch ( action ) {
case ENABLE_RELAY_DO_OR:
if ( m_dropOnDismiss ) {
postDelayed( new Runnable() {
public void run() {
askDropRelay();
}
}, 10 );
}
break;
case DELETE_AND_EXIT:
finish();
break;
}
}
} // dlgButtonClicked
public void inviteChoiceMade( Action action, InviteMeans means,
Object[] params )
@ -1167,8 +1170,8 @@ public class BoardDelegate extends DelegateBase
RequestCode.BT_INVITE_RESULT );
break;
case SMS:
SMSInviteDelegate.launchForResult( m_activity, m_nMissing, info,
RequestCode.SMS_INVITE_RESULT );
Perms23.tryGetPerms( this, Perm.SEND_SMS, R.string.sms_invite_rationale,
Action.INVITE_SMS, this, m_nMissing, info );
break;
case RELAY:
RelayInviteDelegate.launchForResult( m_activity, m_nMissing,
@ -1269,13 +1272,8 @@ public class BoardDelegate extends DelegateBase
break;
case SMS_SEND_FAILED:
case SMS_SEND_FAILED_NORADIO:
// if ( null != m_jniThread ) {
// boolean accepted =
// MultiService.MultiEvent.SMS_RECEIVE_OK == event
// || MultiService.MultiEvent.SMS_SEND_OK == event;
// m_jniThread.handle( JNICmd.CMD_DRAW_SMS_STATUS, accepted );
// }
case SMS_SEND_FAILED_NOPERMISSION:
DbgUtils.showf( m_activity, R.string.sms_send_failed );
break;
default:
@ -1468,6 +1466,7 @@ public class BoardDelegate extends DelegateBase
makeConfirmThenBuilder( R.string.connstat_net_noaddr,
Action.DELETE_AND_EXIT )
.setPosButton( R.string.list_item_delete )
.setNegButton( R.string.button_close_game )
.show();
}
@ -1629,8 +1628,7 @@ public class BoardDelegate extends DelegateBase
DbgUtils.logi( TAG, "handleConndMessage(): toastStr: %s", toastStr );
m_toastStr = toastStr;
if ( naMsg == 0 ) {
dlgButtonClicked( Action.SHOW_EXPL_ACTION,
AlertDialog.BUTTON_POSITIVE, null );
onPosButton( Action.SHOW_EXPL_ACTION, null );
} else {
makeNotAgainBuilder( naMsg, naKey, Action.SHOW_EXPL_ACTION )
.show();
@ -2092,17 +2090,21 @@ public class BoardDelegate extends DelegateBase
private void doResume( boolean isStart )
{
boolean success = true;
boolean firstStart = null == m_handler;
if ( firstStart ) {
m_handler = new Handler();
m_blockingDlgID = DlgID.NONE;
m_jniThreadRef.configure( m_activity, m_view, m_utils, this,
success = m_jniThreadRef.configure( m_activity, m_view, m_utils, this,
makeJNIHandler() );
if ( success ) {
m_jniGamePtr = m_jniThreadRef.getGamePtr();
Assert.assertNotNull( m_jniGamePtr );
}
}
if ( success ) {
try {
resumeGame( isStart );
if ( !isStart ) {
@ -2110,6 +2112,11 @@ public class BoardDelegate extends DelegateBase
ConnStatusHandler.setHandler( this );
}
} catch ( GameUtils.NoSuchGameException nsge ) {
success = false;
}
}
if ( !success ) {
finish();
}
}
@ -2226,21 +2233,16 @@ public class BoardDelegate extends DelegateBase
&& null == m_permCbck ) { // already asked?
m_permCbck = new Perms23.PermCbck() {
@Override
public void onPermissionResult( Map<Perms23.Perm,
Boolean> perms )
{
ActionPair pair = new ActionPair( Action.DROP_SMS_ACTION,
R.string.remove_sms );
if ( ! perms.get(Perms23.Perm.SEND_SMS) ) {
makeNotAgainBuilder( R.string.not_again_missing_perms,
R.string.key_notagain_missing_perms )
.setActionPair( pair )
public void onPermissionResult( Map<Perm, Boolean> perms ) {
if ( ! perms.get(Perm.SEND_SMS) ) {
makeConfirmThenBuilder( R.string.missing_perms,
Action.DROP_SMS_ACTION )
.setNegButton(R.string.remove_sms)
.show();
}
}
};
new Perms23.Builder(Perms23.Perm.SEND_SMS)
new Perms23.Builder(Perm.SEND_SMS)
.asyncQuery( m_activity, m_permCbck );
}
}
@ -2567,6 +2569,7 @@ public class BoardDelegate extends DelegateBase
}
}
private boolean m_needsResize = false;
private void updateToolbar()
{
if ( null != m_toolbar ) {
@ -2579,6 +2582,14 @@ public class BoardDelegate extends DelegateBase
m_toolbar.update( Buttons.BUTTON_CHAT, m_gsi.canChat );
m_toolbar.update( Buttons.BUTTON_BROWSE_DICT,
null != m_gi.dictName( m_view.getCurPlayer() ) );
int count = m_toolbar.enabledCount();
if ( 0 == count ) {
m_needsResize = true;
} else if ( m_needsResize && 0 < count ) {
m_needsResize = false;
m_view.orientationChanged();
}
}
}

View file

@ -23,7 +23,6 @@ package org.eehouse.android.xw4;
import android.os.Bundle;
public class BoardFrag extends XWFragment {
private static final String TAG = BoardFrag.class.getSimpleName();
public BoardFrag() {}

View file

@ -109,7 +109,7 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
} else if ( XwJNI.board_containsPt( m_jniGamePtr, xx, yy ) ) {
handle( JNIThread.JNICmd.CMD_PEN_DOWN, xx, yy );
} else {
DbgUtils.logd( TAG, "BoardView.onTouchEvent(): in white space" );
DbgUtils.logd( TAG, "onTouchEvent(): in white space" );
}
break;
case MotionEvent.ACTION_MOVE:
@ -160,7 +160,7 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
if ( BoardContainer.getIsPortrait() != (m_dims.height > m_dims.width) ) {
// square possible; will break above!
Assert.assertTrue( m_dims.height != m_dims.width );
DbgUtils.logd( TAG, "BoardView.onMeasure: discarding m_dims" );
DbgUtils.logd( TAG, "onMeasure: discarding m_dims" );
if ( ++m_dimsTossCount < 4 ) {
m_dims = null;
m_layoutWidth = m_layoutHeight = 0;
@ -187,7 +187,7 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
width = minWidth;
}
setMeasuredDimension( width, height );
DbgUtils.logd( TAG, "BoardView.onMeasure: calling setMeasuredDimension( width=%d, height=%d )",
DbgUtils.logd( TAG, "onMeasure: calling setMeasuredDimension( width=%d, height=%d )",
width, height );
}
@ -214,7 +214,7 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
ConnStatusHandler.draw( m_context, canvas, getResources(),
m_connTypes, m_isSolo );
} else {
DbgUtils.logd( TAG, "BoardView.onDraw(): board not laid out yet" );
DbgUtils.logd( TAG, "onDraw(): board not laid out yet" );
}
}
}

View file

@ -23,7 +23,6 @@ package org.eehouse.android.xw4;
import android.os.Bundle;
public class ChatActivity extends XWActivity {
private static final String TAG = ChatActivity.class.getSimpleName();
@Override
public void onCreate( Bundle savedInstanceState )

View file

@ -226,19 +226,17 @@ public class ChatDelegate extends DelegateBase {
}
@Override
public void dlgButtonClicked( Action action, int which, Object[] params )
public void onPosButton( Action action, Object[] params )
{
switch ( action ) {
case CLEAR_ACTION:
if ( AlertDialog.BUTTON_POSITIVE == which ) {
DBUtils.clearChatHistory( m_activity, m_rowid );
TableLayout layout =
(TableLayout)findViewById( R.id.chat_history );
layout.removeAllViews();
}
break;
default:
super.dlgButtonClicked( action, which, params );
super.onPosButton( action, params );
}
}

View file

@ -22,7 +22,6 @@ package org.eehouse.android.xw4;
import android.os.Bundle;
public class ChatFrag extends XWFragment {
private static final String TAG = ChatFrag.class.getSimpleName();
public ChatFrag() {}

View file

@ -37,7 +37,6 @@ import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnTypeSet;
import org.eehouse.android.xw4.loc.LocUtils;
public class ConnViaViewLayout extends LinearLayout {
private static final String TAG = ConnViaViewLayout.class.getSimpleName();
private CommsConnTypeSet m_curSet;
private DlgDelegate.HasDlgDelegate m_dlgDlgt;
private Activity m_activity;
@ -78,23 +77,6 @@ public class ConnViaViewLayout extends LinearLayout {
}
private void addConnections()
{
// We need SMS and PHONE permission to check if we can support SMS. So
// ask for it here. When we get what we're getting, proceed to
// actually check for what's supported. Those methods will return
// false if they don't have the permission they need.
new Perms23.Builder( Perms23.Perm.READ_PHONE_STATE )
.asyncQuery( m_activity, new Perms23.PermCbck() {
@Override
public void onPermissionResult( Map<Perms23.Perm,
Boolean> granted ) {
addConnectionsPostPermCheck();
}
} );
}
private void addConnectionsPostPermCheck()
{
LinearLayout list = (LinearLayout)findViewById( R.id.conn_types );
list.removeAllViews(); // in case being reused

View file

@ -88,6 +88,8 @@ public class DelegateBase implements DlgClickNotify,
LocUtils.xlateTitle( m_activity );
}
public Activity getActivity() { return m_activity; }
// Does nothing unless overridden. These belong in an interface.
protected void init( Bundle savedInstanceState ) { Assert.fail(); }
protected void onSaveInstanceState( Bundle outState ) {}
@ -103,6 +105,12 @@ public class DelegateBase implements DlgClickNotify,
protected void requestWindowFeature( int feature ) {}
protected void tryGetPerms( Perms23.Perm perm, int rationale,
Action action, Object... params )
{
Perms23.tryGetPerms( this, perm, rationale, action, this, params );
}
// Fragments only
protected View inflateView( LayoutInflater inflater, ViewGroup container )
{
@ -628,14 +636,13 @@ public class DelegateBase implements DlgClickNotify,
//////////////////////////////////////////////////////////////////////
// DlgDelegate.DlgClickNotify interface
//////////////////////////////////////////////////////////////////////
public void dlgButtonClicked( Action action, int button, Object[] params )
public void onPosButton( Action action, Object[] params )
{
boolean handled = false;
if ( AlertDialog.BUTTON_POSITIVE == button ) {
DbgUtils.logd( TAG, "%s.posButtonClicked(%s)", getClass().getSimpleName(),
action.toString() );
switch( action ) {
case ENABLE_SMS_ASK:
showSMSEnableDialog( Action.ENABLE_SMS_DO, params );
handled = true;
break;
case ENABLE_SMS_DO:
XWPrefs.setSMSEnabled( m_activity, true );
@ -645,36 +652,35 @@ public class DelegateBase implements DlgClickNotify,
break;
case ENABLE_RELAY_DO:
RelayService.setEnabled( m_activity, true );
handled = true;
break;
case PERMS_QUERY:
Perms23.onGotPermsAction( true, params );
break;
default:
Assert.fail();
DbgUtils.logd( TAG, "unhandled action %s", action.toString() );
Assert.assertTrue( !BuildConfig.DEBUG );
break;
}
}
if ( !handled && BuildConfig.DEBUG ) {
String buttonName = null;
switch( button ) {
case AlertDialog.BUTTON_POSITIVE:
buttonName = "positive";
break;
case AlertDialog.BUTTON_NEGATIVE:
buttonName = "negative";
break;
case AlertDialog.BUTTON_NEUTRAL:
buttonName = "neutral";
break;
case DlgDelegate.DISMISS_BUTTON:
buttonName = "dismiss";
public void onNegButton( Action action, Object[] params )
{
// DbgUtils.logd( TAG, "%s.negButtonClicked(%s)", getClass().getSimpleName(),
// action.toString() );
switch ( action ) {
case PERMS_QUERY:
Perms23.onGotPermsAction( false, params );
break;
default:
Assert.fail();
DbgUtils.logd( TAG, "onNegButton: unhandled action %s", action.toString() );
break;
}
DbgUtils.logi( TAG, "dlgButtonClicked(action=%s button=%s): UNHANDLED",
action.toString(), buttonName );
}
public void onDismissed( Action action, Object[] params )
{
DbgUtils.logd( TAG, "%s.dlgDismissed(%s)", getClass().getSimpleName(),
action.toString() );
}
public void inviteChoiceMade( Action action, DlgClickNotify.InviteMeans means, Object[] params )

View file

@ -23,7 +23,6 @@ package org.eehouse.android.xw4;
import android.os.Bundle;
public class DictBrowseActivity extends XWActivity {
private static final String TAG = DictBrowseActivity.class.getSimpleName();
private DictBrowseDelegate m_dlgt;

View file

@ -300,9 +300,9 @@ public class DictBrowseDelegate extends DelegateBase
// DlgDelegate.DlgClickNotify interface
//////////////////////////////////////////////////
@Override
public void dlgButtonClicked( Action action, int which, Object[] params )
public void onPosButton( Action action, Object[] params )
{
Assert.assertTrue( Action.FINISH_ACTION == action );
Assert.assertTrue( !BuildConfig.DEBUG || Action.FINISH_ACTION==action );
finish();
}

View file

@ -22,7 +22,6 @@ package org.eehouse.android.xw4;
import android.os.Bundle;
public class DictBrowseFrag extends XWFragment {
private static final String TAG = DictBrowseFrag.class.getSimpleName();
public DictBrowseFrag() {}

View file

@ -26,7 +26,6 @@ import android.util.AttributeSet;
import java.util.ArrayList;
public class DictListPreference extends XWListPreference {
private static final String TAG = DictListPreference.class.getSimpleName();
public DictListPreference( Context context, AttributeSet attrs )
{

View file

@ -131,6 +131,11 @@ public class DictUtils {
// changes?
}
public static boolean needsStoragePermission( DictLoc loc )
{
return DictLoc.DOWNLOAD == loc;
}
private static void tryDir( Context context, File dir, boolean strict,
DictLoc loc, ArrayList<DictAndLoc> al )
{
@ -146,9 +151,17 @@ public class DictUtils {
}
}
private static Boolean s_hadStorage = null;
public static DictAndLoc[] dictList( Context context )
{
if ( null == s_dictListCache ) {
// Note: if STORAGE permission is changed the set being returned here
// will change. Might want to check for that and invalidate this list
// if it's changed.
boolean haveStorage = Perms23.havePermission( Perms23.Perm.STORAGE );
boolean permsChanged = null == s_hadStorage
|| haveStorage != s_hadStorage;
if ( permsChanged || null == s_dictListCache ) {
ArrayList<DictAndLoc> al = new ArrayList<DictAndLoc>();
for ( String file : getAssets( context ) ) {
@ -171,6 +184,7 @@ public class DictUtils {
s_dictListCache =
al.toArray( new DictUtils.DictAndLoc[al.size()] );
s_hadStorage = new Boolean( haveStorage );
}
return s_dictListCache;
}

View file

@ -23,7 +23,6 @@ package org.eehouse.android.xw4;
import android.os.Bundle;
public class DictsActivity extends XWActivity {
private static final String TAG = DictsActivity.class.getSimpleName();
// I can't provide a subclass of MenuItem to hold DictAndLoc, so
// settle for a hash on the side.

View file

@ -52,8 +52,10 @@ import org.eehouse.android.xw4.DictUtils.DictLoc;
import org.eehouse.android.xw4.DlgDelegate.Action;
import org.eehouse.android.xw4.DwnldDelegate.DownloadFinishedListener;
import org.eehouse.android.xw4.DwnldDelegate.OnGotLcDictListener;
import org.eehouse.android.xw4.Perms23.Perm;
import org.eehouse.android.xw4.jni.GameSummary;
import org.eehouse.android.xw4.loc.LocUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@ -373,6 +375,12 @@ public class DictsDelegate extends ListDelegateBase
Button btn =
dlg.getButton( AlertDialog.BUTTON_POSITIVE );
btn.setEnabled( true );
// Ask for STORAGE (but do nothing if not granted)
if ( DictLoc.DOWNLOAD == itemToRealLoc( item ) ) {
new Perms23.Builder( Perm.STORAGE )
.asyncQuery( m_activity );
}
}
};
@ -380,23 +388,8 @@ public class DictsDelegate extends ListDelegateBase
public void onClick( DialogInterface dlg, int item ) {
DictsDelegate self = curThis();
DictLoc toLoc = self.itemToRealLoc( moveTo[0] );
for ( XWListItem selItem : selItems ) {
DictLoc fromLoc = (DictLoc)selItem.getCached();
String name = selItem.getText();
if ( fromLoc == toLoc ) {
DbgUtils.logw( TAG, "not moving %s: same loc", name );
} else if ( DictUtils.moveDict( self.m_activity,
name, fromLoc,
toLoc ) ) {
selItem.setComment( self.m_locNames[toLoc.ordinal()] );
selItem.setCached( toLoc );
selItem.invalidate();
DBUtils.dictsMoveInfo( self.m_activity, name,
fromLoc, toLoc );
} else {
DbgUtils.logw( TAG, "moveDict(%s) failed", name );
}
}
Assert.assertTrue( self == DictsDelegate.this );
moveDicts( selItems, toLoc );
}
};
@ -541,6 +534,9 @@ public class DictsDelegate extends ListDelegateBase
makeNotAgainBuilder( R.string.not_again_dicts, R.string.key_na_dicts )
.show();
tryGetPerms( Perm.STORAGE, R.string.dicts_storage_rationale,
Action.STORAGE_CONFIRMED );
} // init
@Override
@ -658,6 +654,46 @@ public class DictsDelegate extends ListDelegateBase
return handled;
}
private void moveDicts( XWListItem[] selItems, DictLoc toLoc )
{
if ( DictUtils.needsStoragePermission( toLoc ) ) {
tryGetPerms( Perm.STORAGE, R.string.move_dict_rationale,
Action.MOVE_CONFIRMED, selItems, toLoc );
} else {
moveDictsWithPermission( selItems, toLoc );
}
}
private void moveDictsWithPermission( Object[] params )
{
XWListItem[] selItems = (XWListItem[])params[0];
DictLoc toLoc = (DictLoc)params[1];
moveDictsWithPermission( selItems, toLoc );
}
private void moveDictsWithPermission( XWListItem[] selItems, DictLoc toLoc )
{
for ( XWListItem selItem : selItems ) {
DictLoc fromLoc = (DictLoc)selItem.getCached();
String name = selItem.getText();
if ( fromLoc == toLoc ) {
DbgUtils.logw( TAG, "not moving %s: same loc", name );
} else if ( DictUtils.moveDict( m_activity,
name, fromLoc,
toLoc ) ) {
selItem.setComment( m_locNames[toLoc.ordinal()] );
selItem.setCached( toLoc );
selItem.invalidate();
DBUtils.dictsMoveInfo( m_activity, name,
fromLoc, toLoc );
} else {
DbgUtils.showf( m_activity, R.string.toast_no_permission );
DbgUtils.logw( TAG, "moveDict(%s) failed", name );
}
}
}
private void switchShowingRemote( boolean showRemote )
{
// if showing for the first time, download remote info and let the
@ -865,9 +901,9 @@ public class DictsDelegate extends ListDelegateBase
//////////////////////////////////////////////////////////////////////
// DlgDelegate.DlgClickNotify interface
//////////////////////////////////////////////////////////////////////
public void dlgButtonClicked( Action action, int which, Object[] params )
@Override
public void onPosButton( Action action, Object[] params )
{
if ( DialogInterface.BUTTON_POSITIVE == which ) {
switch( action ) {
case DELETE_DICT_ACTION:
XWListItem[] items = (XWListItem[])params[0];
@ -892,9 +928,14 @@ public class DictsDelegate extends ListDelegateBase
}
DwnldDelegate.downloadDictsInBack( m_activity, uris, names, this );
break;
case MOVE_CONFIRMED:
moveDictsWithPermission( params );
break;
case STORAGE_CONFIRMED:
mkListAdapter();
break;
default:
Assert.fail();
}
super.onPosButton( action, params );
}
}

View file

@ -22,7 +22,6 @@ package org.eehouse.android.xw4;
import android.os.Bundle;
public class DictsFrag extends XWFragment {
private static final String TAG = DictsFrag.class.getSimpleName();
public DictsFrag() {}

View file

@ -25,7 +25,6 @@ import android.net.Uri;
import android.os.Bundle;
public class DispatchNotify extends Activity {
private static final String TAG = DispatchNotify.class.getSimpleName();
@Override
protected void onCreate( Bundle savedInstanceState )

View file

@ -93,12 +93,13 @@ public class DlgDelegate {
NFC_TO_SELF,
DROP_RELAY_ACTION,
DROP_SMS_ACTION,
RETRY_PHONE_STATE_ACTION,
INVITE_SMS,
// Dict Browser
FINISH_ACTION,
DELETE_DICT_ACTION,
UPDATE_DICTS_ACTION,
MOVE_CONFIRMED,
// Game configs
LOCKED_CHANGE_ACTION,
@ -112,7 +113,6 @@ public class DlgDelegate {
CLEAR_ACTION,
USE_IMMOBILE_ACTION,
POST_WARNING_ACTION,
RETRY_CONTACTS_ACTION,
// BT Invite
OPEN_BT_PREFS_ACTION,
@ -121,6 +121,9 @@ public class DlgDelegate {
SL_CLEAR_ACTION,
SL_COPY_ACTION,
// DwnldDelegate && GamesListDelegate
STORAGE_CONFIRMED,
// clasify me
ENABLE_SMS_ASK,
ENABLE_SMS_DO,
@ -128,6 +131,8 @@ public class DlgDelegate {
ENABLE_RELAY_DO,
ENABLE_RELAY_DO_OR,
DISABLE_RELAY_DO,
ASKED_PHONE_STATE,
PERMS_QUERY,
}
public static class ActionPair {
@ -164,6 +169,7 @@ public class DlgDelegate {
protected int m_negButton = android.R.string.cancel;
protected Action m_action;
protected Object[] m_params;
protected int m_titleId = 0;
public DlgDelegateBuilder( String msg, Action action )
{ m_msgString = msg; m_action = action; }
@ -195,11 +201,13 @@ public class DlgDelegate {
public OkOnlyBuilder(int msgId) { super( msgId, Action.SKIP_CALLBACK ); }
public OkOnlyBuilder setAction( Action action )
{ m_action = action; return this; }
public OkOnlyBuilder setTitle( int titleId )
{ m_titleId = titleId; return this; }
@Override
public void show()
{
showOKOnlyDialogThen( m_msgString, m_action, m_params );
showOKOnlyDialogThen( m_msgString, m_action, m_params, m_titleId );
}
}
@ -207,11 +215,14 @@ public class DlgDelegate {
public ConfirmThenBuilder(String msg, Action action) {super(msg, action);}
public ConfirmThenBuilder(int msgId, Action action) {super(msgId, action);}
public ConfirmThenBuilder setTitle( int titleId )
{ m_titleId = titleId; return this; }
@Override
public void show()
{
showConfirmThen( m_nakey, m_onNA, m_msgString, m_posButton,
m_negButton, m_action, m_params );
m_negButton, m_action, m_titleId, m_params );
}
}
@ -296,7 +307,10 @@ public class DlgDelegate {
public static enum InviteMeans {
SMS, EMAIL, NFC, BLUETOOTH, CLIPBOARD, RELAY, WIFIDIRECT,
};
void dlgButtonClicked( Action action, int button, Object[] params );
void onPosButton( Action action, Object[] params );
void onNegButton( Action action, Object[] params );
void onDismissed( Action action, Object[] params );
void inviteChoiceMade( Action action, InviteMeans means, Object[] params );
}
public interface HasDlgDelegate {
@ -411,12 +425,13 @@ public class DlgDelegate {
}
private void showOKOnlyDialogThen( String msg, Action action,
Object[] params )
Object[] params, int titleId )
{
// Assert.assertNull( m_dlgStates );
DlgState state = new DlgState( DlgID.DIALOG_OKONLY )
.setMsg( msg )
.setParams( params )
.setTitle( titleId )
.setAction(action);
addState( state );
showDialog( DlgID.DIALOG_OKONLY );
@ -433,7 +448,7 @@ public class DlgDelegate {
}
// Puts up alert asking to choose a reason to enable SMS, and on dismiss
// calls dlgButtonClicked with the action and in params a Boolean
// calls onPosButton/onNegButton with the action and in params a Boolean
// indicating whether enabling is now ok.
public void showSMSEnableDialog( Action action, Object... params )
{
@ -455,9 +470,7 @@ public class DlgDelegate {
post( new Runnable() {
public void run() {
m_clickCallback
.dlgButtonClicked( action,
AlertDialog.BUTTON_POSITIVE,
params );
.onPosButton( action, params );
}
});
}
@ -470,8 +483,9 @@ public class DlgDelegate {
}
}
private void showConfirmThen( NAKey nakey, Runnable onNA, String msg, int posButton,
int negButton, Action action, Object[] params )
private void showConfirmThen( NAKey nakey, Runnable onNA, String msg,
int posButton, int negButton, Action action,
int titleId, Object[] params )
{
if ( null != nakey ) {
Assert.assertNull( onNA );
@ -483,6 +497,7 @@ public class DlgDelegate {
.setPosButton( posButton )
.setNegButton( negButton )
.setAction( action )
.setTitle( titleId )
.setParams( params );
addState( state );
showDialog( DlgID.CONFIRM_THEN );
@ -661,7 +676,7 @@ public class DlgDelegate {
private Dialog createOKDialog( DlgState state, DlgID dlgID )
{
Dialog dialog = LocUtils.makeAlertBuilder( m_activity )
.setTitle( R.string.info_title )
.setTitle( state.m_titleId == 0 ? R.string.info_title : state.m_titleId )
.setMessage( state.m_msg )
.setPositiveButton( android.R.string.ok, null )
.create();
@ -687,10 +702,7 @@ public class DlgDelegate {
OnClickListener lstnr = new OnClickListener() {
public void onClick( DialogInterface dlg, int item ) {
checkNotAgainCheck( state, naView );
m_clickCallback.
dlgButtonClicked( more.action,
AlertDialog.BUTTON_POSITIVE,
more.params );
m_clickCallback.onPosButton( more.action, more.params );
}
};
builder.setNegativeButton( more.buttonStr, lstnr );
@ -710,7 +722,7 @@ public class DlgDelegate {
OnClickListener lstnr = mkCallbackClickListener( state, naView );
AlertDialog.Builder builder = LocUtils.makeAlertBuilder( m_activity )
.setTitle( R.string.query_title )
.setTitle( state.m_titleId == 0 ? R.string.query_title : state.m_titleId )
.setView( naView )
.setPositiveButton( state.m_posButton, lstnr )
.setNegativeButton( state.m_negButton, lstnr );
@ -851,9 +863,7 @@ public class DlgDelegate {
layout.findViewById( R.id.confirm_sms_reasons );
boolean enabled = 0 < reasons.getSelectedItemPosition();
Assert.assertTrue( enabled );
m_clickCallback.dlgButtonClicked( state.m_action,
AlertDialog.BUTTON_POSITIVE,
state.m_params );
m_clickCallback.onPosButton( state.m_action, state.m_params );
}
};
@ -902,9 +912,21 @@ public class DlgDelegate {
checkNotAgainCheck( state, naView );
if ( Action.SKIP_CALLBACK != state.m_action ) {
m_clickCallback.dlgButtonClicked( state.m_action,
button,
switch ( button ) {
case AlertDialog.BUTTON_POSITIVE:
m_clickCallback.onPosButton( state.m_action,
state.m_params );
break;
case AlertDialog.BUTTON_NEGATIVE:
m_clickCallback.onNegButton( state.m_action,
state.m_params );
break;
default:
DbgUtils.loge( TAG, "unexpected button %d",
button );
// ignore on release builds
Assert.assertFalse( BuildConfig.DEBUG );
}
}
}
};
@ -933,8 +955,7 @@ public class DlgDelegate {
public void onDismiss( DialogInterface di ) {
dropState( state );
if ( Action.SKIP_CALLBACK != state.m_action ) {
m_clickCallback.dlgButtonClicked( state.m_action,
DISMISS_BUTTON,
m_clickCallback.onDismissed( state.m_action,
state.m_params );
}
m_activity.removeDialog( id );

View file

@ -27,7 +27,6 @@ import org.eehouse.android.xw4.DlgDelegate.Action;
import org.eehouse.android.xw4.DlgDelegate.ActionPair;
public class DlgState implements Parcelable {
private static final String TAG = DlgState.class.getSimpleName();
public DlgID m_id;
public String m_msg;
public int m_posButton;
@ -38,6 +37,7 @@ public class DlgState implements Parcelable {
// These can't be serialized!!!!
public Object[] m_params;
public Runnable m_onNAChecked;
public int m_titleId;
public DlgState( DlgID dlgID )
{
@ -60,6 +60,8 @@ public class DlgState implements Parcelable {
{ m_posButton = id; return this; }
public DlgState setNegButton( int id )
{ m_negButton = id; return this; }
public DlgState setTitle( int id )
{ m_titleId = id; return this; }
public int describeContents() {
return 0;
@ -71,6 +73,7 @@ public class DlgState implements Parcelable {
out.writeInt( m_negButton );
out.writeInt( null == m_action ? -1 : m_action.ordinal() );
out.writeInt( m_prefsKey );
out.writeInt( m_titleId );
out.writeString( m_msg );
}
@ -83,6 +86,7 @@ public class DlgState implements Parcelable {
int tmp = in.readInt();
Action action = 0 > tmp ? null : Action.values()[tmp];
int prefsKey = in.readInt();
int titleId = in.readInt();
String msg = in.readString();
DlgState state = new DlgState(id)
.setMsg( msg )

View file

@ -24,7 +24,6 @@ import android.os.Bundle;
import android.view.Window;
public class DwnldActivity extends XWActivity {
private static final String TAG = DwnldActivity.class.getSimpleName();
@Override
protected void onCreate( Bundle savedInstanceState )

View file

@ -21,6 +21,7 @@
package org.eehouse.android.xw4;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
@ -45,6 +46,10 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eehouse.android.xw4.DlgDelegate.Action;
import org.eehouse.android.xw4.Perms23.Perm;
public class DwnldDelegate extends ListDelegateBase {
private static final String TAG = DwnldDelegate.class.getSimpleName();
@ -106,12 +111,15 @@ public class DwnldDelegate extends ListDelegateBase {
item.findViewById( R.id.progress_bar );
}
public void setLabel( String text )
public DownloadFilesTask setLabel( String text )
{
TextView tv = (TextView)m_listItem.findViewById( R.id.dwnld_message );
tv.setText( text );
return this;
}
private boolean forApp() { return m_isApp; }
@Override
protected Void doInBackground( Void... unused )
{
@ -286,7 +294,16 @@ public class DwnldDelegate extends ListDelegateBase {
if ( 0 == m_dfts.size() ) {
finish();
} else if ( !anyNeedsStorage() ) {
doWithPermissions( uris );
} else {
tryGetPerms( Perm.STORAGE, R.string.download_rationale,
Action.STORAGE_CONFIRMED, (Object)uris );
}
}
private void doWithPermissions( Uri[] uris )
{
Assert.assertTrue( m_dfts.size() == uris.length );
mkListAdapter();
@ -296,12 +313,25 @@ public class DwnldDelegate extends ListDelegateBase {
String msg =
getString( R.string.downloading_dict_fmt, showName );
dft = m_dfts.get( ii );
dft.setLabel( msg );
dft.execute();
m_dfts.get( ii )
.setLabel( msg )
.execute();
}
} // doWithPermissions
private boolean anyNeedsStorage()
{
boolean result = false;
DictUtils.DictLoc loc = XWPrefs.getDefaultLoc( m_activity );
for ( DownloadFilesTask task : m_dfts ) {
if ( task.forApp() || DictUtils.DictLoc.DOWNLOAD == loc ) {
result = true;
break;
}
}
} // init
return result;
}
@Override
protected boolean handleBackPressed()
@ -315,6 +345,30 @@ public class DwnldDelegate extends ListDelegateBase {
return super.handleBackPressed();
}
@Override
public void onPosButton( Action action, Object[] params )
{
switch ( action ) {
case STORAGE_CONFIRMED:
doWithPermissions( (Uri[])params[0] );
break;
default:
super.onPosButton( action, params );
}
}
@Override
public void onNegButton( Action action, Object[] params )
{
switch ( action ) {
case STORAGE_CONFIRMED:
finish();
break;
default:
super.onPosButton( action, params );
}
}
private void mkListAdapter()
{
setListAdapter( new ImportListAdapter() );

View file

@ -36,7 +36,6 @@ import android.widget.SeekBar;
import org.eehouse.android.xw4.loc.LocUtils;
public class EditColorPreference extends DialogPreference {
private static final String TAG = EditColorPreference.class.getSimpleName();
private Context m_context;
private int m_curColor;

View file

@ -26,7 +26,6 @@ import android.util.AttributeSet;
import android.widget.LinearLayout;
public class ExpiringLinearLayout extends LinearLayout {
private static final String TAG = ExpiringLinearLayout.class.getSimpleName();
private ExpiringDelegate m_delegate;
public ExpiringLinearLayout( Context context, AttributeSet as ) {

View file

@ -23,7 +23,6 @@ package org.eehouse.android.xw4;
import android.os.Bundle;
public class GameConfigActivity extends XWActivity {
private static final String TAG = GameConfigActivity.class.getSimpleName();
@Override
public void onCreate( Bundle savedInstanceState )

View file

@ -684,12 +684,9 @@ public class GameConfigDelegate extends DelegateBase
}
@Override
public void dlgButtonClicked( Action action, int button, Object[] params )
public void onPosButton( Action action, Object[] params )
{
boolean callSuper = false;
Assert.assertTrue( curThis() == this );
if ( AlertDialog.BUTTON_POSITIVE == button ) {
switch( action ) {
case LOCKED_CHANGE_ACTION:
handleLockedChange();
@ -708,25 +705,30 @@ public class GameConfigDelegate extends DelegateBase
true );
setupRelayStuffIf( true );
break;
case ASKED_PHONE_STATE:
showDialog( DlgID.CHANGE_CONN );
break;
default:
callSuper = true;
super.onPosButton( action, params );
}
} else if ( AlertDialog.BUTTON_NEGATIVE == button ) {
}
@Override
public void onNegButton( Action action, Object[] params )
{
switch ( action ) {
case DELETE_AND_EXIT:
showConnAfterCheck();
break;
case ASKED_PHONE_STATE:
showDialog( DlgID.CHANGE_CONN );
break;
default:
callSuper = true;
super.onNegButton( action, params );
break;
}
} else {
callSuper = true;
}
if ( callSuper ) {
super.dlgButtonClicked( action, button, params );
}
}
public void onClick( View view )
@ -752,7 +754,7 @@ public class GameConfigDelegate extends DelegateBase
} else if ( m_refreshRoomsButton == view ) {
refreshNames();
} else if ( m_changeConnButton == view ) {
showDialog( DlgID.CHANGE_CONN );
showConnAfterCheck();
} else if ( m_playButton == view ) {
// Launch BoardActivity for m_name, but ONLY IF user
// confirms any changes required. So we either launch
@ -780,6 +782,17 @@ public class GameConfigDelegate extends DelegateBase
}
} // onClick
private void showConnAfterCheck()
{
if ( null == SMSService.getPhoneInfo( m_activity ) ) {
Perms23.tryGetPerms( this, Perms23.Perm.READ_PHONE_STATE,
R.string.phone_state_rationale,
Action.ASKED_PHONE_STATE, this );
} else {
showDialog( DlgID.CHANGE_CONN );
}
}
private void saveAndClose( boolean forceNew )
{
DbgUtils.logi( TAG, "saveAndClose(forceNew=%b)", forceNew );

View file

@ -22,7 +22,6 @@ package org.eehouse.android.xw4;
import android.os.Bundle;
public class GameConfigFrag extends XWFragment {
private static final String TAG = GameConfigFrag.class.getSimpleName();
public GameConfigFrag() {}

View file

@ -30,7 +30,6 @@ import android.widget.TextView;
import org.eehouse.android.xw4.loc.LocUtils;
public class GameNamer extends LinearLayout {
private static final String TAG = GameNamer.class.getSimpleName();
private Context m_context;

View file

@ -113,8 +113,6 @@ public class GameUtils {
CurGameInfo gi = new CurGameInfo( context );
CommsAddrRec addr = null;
// loadMakeGame, if making a new game, will add comms as long
// as DeviceRole.SERVER_STANDALONE != gi.serverRole
GamePtr gamePtr = loadMakeGame( context, gi, lockSrc );
String[] dictNames = gi.dictNames();
DictUtils.DictPairs pairs = DictUtils.openDicts( context, dictNames );
@ -122,11 +120,6 @@ public class GameUtils {
if ( XwJNI.game_hasComms( gamePtr ) ) {
addr = new CommsAddrRec();
XwJNI.comms_getAddr( gamePtr, addr );
if ( 0 == addr.conTypes.size() ) {
String relayName = XWPrefs.getDefaultRelayHost( context );
int relayPort = XWPrefs.getDefaultRelayPort( context );
XwJNI.comms_getInitialAddr( addr, relayName, relayPort );
}
}
gamePtr.release();
@ -742,74 +735,6 @@ public class GameUtils {
}
}
// public static void launchInviteActivity( Activity activity,
// InviteMeans means,
// String room, String inviteID,
// int lang, String dict,
// int nPlayers )
// {
// Assert.assertNotNull( inviteID );
// if ( InviteMeans.NFC == means ) {
// Utils.showToast( activity, R.string.sms_ready_text );
// } else {
// // NetLaunchInfo nli = new NetLaunchInfo( 0, lang, dict, nPlayers );
// Uri gameUri = NetLaunchInfo.makeLaunchUri( activity, room, inviteID,
// lang, dict, nPlayers );
// String msgString = null == gameUri ? null : gameUri.toString();
// if ( null != msgString ) {
// boolean choseEmail = InviteMeans.EMAIL == means;
// int fmtId = choseEmail? R.string.invite_htm_fmt : R.string.invite_txt_fmt;
// int choiceID;
// String message = LocUtils.getString( activity, fmtId, msgString );
// Intent intent = new Intent();
// if ( choseEmail ) {
// intent.setAction( Intent.ACTION_SEND );
// String subject =
// LocUtils.getString( activity, R.string.invite_subject_fmt,
// room );
// intent.putExtra( Intent.EXTRA_SUBJECT, subject );
// intent.putExtra( Intent.EXTRA_TEXT, Html.fromHtml(message) );
// File attach = null;
// File tmpdir = XWApp.ATTACH_SUPPORTED ?
// DictUtils.getDownloadDir( activity ) : null;
// if ( null != tmpdir ) { // no attachment
// attach = makeJsonFor( tmpdir, room, inviteID, lang,
// dict, nPlayers );
// }
// if ( null == attach ) { // no attachment
// intent.setType( "message/rfc822");
// } else {
// String mime = LocUtils.getString( activity, R.string.invite_mime );
// intent.setType( mime );
// Uri uri = Uri.fromFile( attach );
// intent.putExtra( Intent.EXTRA_STREAM, uri );
// }
// choiceID = R.string.invite_chooser_email;
// } else {
// intent.setAction( Intent.ACTION_VIEW );
// intent.setType( "vnd.android-dir/mms-sms" );
// intent.putExtra( "sms_body", message );
// choiceID = R.string.invite_chooser_sms;
// }
// String choiceType = LocUtils.getString( activity, choiceID );
// String chooserMsg =
// LocUtils.getString( activity, R.string.invite_chooser_fmt,
// choiceType );
// activity.startActivity( Intent.createChooser( intent, chooserMsg ) );
// }
// }
// }
public static String[] dictNames( Context context, GameLock lock )
{
byte[] stream = savedGame( context, lock );
@ -840,6 +765,12 @@ public class GameUtils {
return gameDictsHere( context, rowid, null, null );
}
public static boolean gameDictsHere( Context context, GameLock lock )
{
String[] gameDicts = dictNames( context, lock );
return gameDictsHere( context, null, gameDicts );
}
// Return true if all dicts present. Return list of those that
// are not.
public static boolean gameDictsHere( Context context, long rowid,
@ -847,6 +778,13 @@ public class GameUtils {
int[] missingLang )
{
String[] gameDicts = dictNames( context, rowid, missingLang );
return gameDictsHere( context, missingNames, gameDicts );
}
public static boolean gameDictsHere( Context context,
String[][] missingNames,
String[] gameDicts )
{
HashSet<String> missingSet;
DictUtils.DictAndLoc[] installed = DictUtils.dictList( context );

View file

@ -53,7 +53,9 @@ import org.eehouse.android.xw4.DlgDelegate.ActionPair;
import org.eehouse.android.xw4.DlgDelegate.NAKey;
import org.eehouse.android.xw4.DwnldDelegate.DownloadFinishedListener;
import org.eehouse.android.xw4.DwnldDelegate.OnGotLcDictListener;
import org.eehouse.android.xw4.Perms23.Perm;
import org.eehouse.android.xw4.jni.CommonPrefs;
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnTypeSet;
import org.eehouse.android.xw4.jni.CommsAddrRec;
import org.eehouse.android.xw4.jni.CurGameInfo;
@ -82,6 +84,7 @@ public class GamesListDelegate extends ListDelegateBase
private static final String SAVE_GROUPID = "SAVE_GROUPID";
private static final String SAVE_DICTNAMES = "SAVE_DICTNAMES";
private static final String SAVE_NEXTSOLO = "SAVE_NEXTSOLO";
private static final String SAVE_REMATCHEXTRAS = "SAVE_REMATCHEXTRAS";
private static final String RELAYIDS_EXTRA = "relayids";
private static final String ROWID_EXTRA = "rowid";
@ -91,6 +94,7 @@ public class GamesListDelegate extends ListDelegateBase
private static final String REMATCH_LANG_EXTRA = "rm_lang";
private static final String REMATCH_PREFS_EXTRA = "rm_prefs";
private static final String REMATCH_NEWNAME_EXTRA = "rm_nnm";
private static final String REMATCH_IS_SOLO = "rm_solo";
private static final String REMATCH_ADDRS_EXTRA = "rm_addrs";
private static final String REMATCH_BTADDR_EXTRA = "rm_btaddr";
private static final String REMATCH_PHONE_EXTRA = "rm_phone";
@ -590,7 +594,7 @@ public class GamesListDelegate extends ListDelegateBase
private boolean m_nextIsSolo;
private Button[] m_newGameButtons;
private boolean m_haveShownGetDict;
private Intent m_rematchIntent;
private Bundle m_rematchExtras;
private Object[] m_newGameParams;
public GamesListDelegate( Delegator delegator, Bundle sis )
@ -867,7 +871,8 @@ public class GamesListDelegate extends ListDelegateBase
public void onClick( DialogInterface dlg, int item ) {
EditText edit = (EditText)((Dialog)dlg)
.findViewById( R.id.edit );
curThis().startRematchWithName( edit );
String gameName = edit.getText().toString();
curThis().startRematchWithName( gameName, true );
}
} )
.create();
@ -912,15 +917,16 @@ public class GamesListDelegate extends ListDelegateBase
break;
case GAMES_LIST_NAME_REMATCH:
if ( null != m_rematchExtras ) {
edit = (TextView)dialog.findViewById( R.id.edit );
edit.setText( m_rematchIntent
.getStringExtra( REMATCH_NEWNAME_EXTRA ) );
boolean solo =
-1 == m_rematchIntent.getIntExtra( REMATCH_ADDRS_EXTRA, -1 );
edit.setText( m_rematchExtras
.getString( REMATCH_NEWNAME_EXTRA ) );
boolean solo = m_rematchExtras.getBoolean( REMATCH_IS_SOLO, true );
ad.setIcon( solo ? R.drawable.sologame__gen
: R.drawable.multigame__gen );
((TextView)dialog.findViewById( R.id.msg ))
.setVisibility( View.GONE );
}
break;
}
}
@ -1031,6 +1037,9 @@ public class GamesListDelegate extends ListDelegateBase
if ( null != m_netLaunchInfo ) {
m_netLaunchInfo.putSelf( outState );
}
if ( null != m_rematchExtras ) {
outState.putBundle( SAVE_REMATCHEXTRAS, m_rematchExtras );
}
}
private void getBundledData( Bundle bundle )
@ -1042,6 +1051,7 @@ public class GamesListDelegate extends ListDelegateBase
m_netLaunchInfo = NetLaunchInfo.makeFrom( bundle );
m_missingDictName = bundle.getString( SAVE_DICTNAMES );
m_nextIsSolo = bundle.getBoolean( SAVE_NEXTSOLO );
m_rematchExtras = bundle.getBundle( SAVE_REMATCHEXTRAS );
}
}
@ -1224,9 +1234,9 @@ public class GamesListDelegate extends ListDelegateBase
}
// DlgDelegate.DlgClickNotify interface
public void dlgButtonClicked( Action action, int which, Object[] params )
@Override
public void onPosButton( Action action, Object[] params )
{
if ( AlertDialog.BUTTON_POSITIVE == which ) {
switch( action ) {
case NEW_NET_GAME:
m_netLaunchInfo = (NetLaunchInfo)params[0];
@ -1316,20 +1326,54 @@ public class GamesListDelegate extends ListDelegateBase
askDefaultName();
break;
default:
Assert.fail();
case ASKED_PHONE_STATE:
rematchWithNameAndPerm( true, params );
break;
case STORAGE_CONFIRMED:
int id = (Integer)params[0];
if ( R.id.games_menu_loaddb == id ) {
DBUtils.loadDB( m_activity );
XWPrefs.clearGroupPositions( m_activity );
mkListAdapter();
} else if ( R.id.games_menu_storedb == id ) {
DBUtils.saveDB( m_activity );
showToast( R.string.db_store_done );
}
} else if ( AlertDialog.BUTTON_NEGATIVE == which ) {
if ( Action.NEW_GAME_DFLT_NAME == action ) {
break;
default:
super.onPosButton( action, params );
}
}
@Override
public void onNegButton( Action action, Object[] params )
{
switch ( action ) {
case NEW_GAME_DFLT_NAME:
m_newGameParams = params;
makeThenLaunchOrConfigure();
break;
case ASKED_PHONE_STATE:
rematchWithNameAndPerm( false, params );
break;
default:
super.onNegButton( action, params );
}
} else if ( DlgDelegate.DISMISS_BUTTON == which ) {
}
@Override
public void onDismissed( Action action, Object[] params )
{
switch( action ) {
case ENABLE_DUALPANE_EXIT:
setDualpaneAndFinish( true );
break;
}
default:
super.onDismissed( action, params );
}
}
@ -1560,34 +1604,10 @@ public class GamesListDelegate extends ListDelegateBase
break;
case R.id.games_menu_loaddb:
new Perms23.Builder( Perms23.Perm.STORAGE )
.asyncQuery( m_activity, new Perms23.PermCbck() {
@Override
public void onPermissionResult( Map<Perms23.Perm,
Boolean> granted )
{
Assert.assertTrue( granted.containsKey(Perms23.Perm.STORAGE) );
if ( granted.get(Perms23.Perm.STORAGE) ) {
DBUtils.loadDB( m_activity );
XWPrefs.clearGroupPositions( m_activity );
mkListAdapter();
}
}
} );
break;
case R.id.games_menu_storedb:
new Perms23.Builder( Perms23.Perm.STORAGE )
.asyncQuery( m_activity, new Perms23.PermCbck() {
@Override
public void onPermissionResult( Map<Perms23.Perm, Boolean> granted )
{
Assert.assertTrue( granted.containsKey( Perms23.Perm.STORAGE ) );
if ( granted.get( Perms23.Perm.STORAGE ) ) {
DBUtils.saveDB( m_activity );
showToast( R.string.db_store_done );
}
}
} );
Perms23.tryGetPerms( this, Perm.STORAGE,
null, Action.STORAGE_CONFIRMED,
this, itemID );
break;
default:
@ -2147,35 +2167,68 @@ public class GamesListDelegate extends ListDelegateBase
private void startRematch( Intent intent )
{
if ( -1 != intent.getLongExtra( REMATCH_ROWID_EXTRA, -1 ) ) {
m_rematchIntent = intent;
m_rematchExtras = intent.getExtras();
showDialog( DlgID.GAMES_LIST_NAME_REMATCH );
}
}
private void startRematchWithName( EditText edit )
private void startRematchWithName( final String gameName,
boolean showRationale )
{
String gameName = edit.getText().toString();
if ( null != gameName && 0 < gameName.length() ) {
Intent intent = m_rematchIntent;
long srcRowID = intent.getLongExtra( REMATCH_ROWID_EXTRA, -1 );
String btAddr = intent.getStringExtra( REMATCH_BTADDR_EXTRA );
String phone = intent.getStringExtra( REMATCH_PHONE_EXTRA );
String relayID = intent.getStringExtra( REMATCH_RELAYID_EXTRA );
String p2pMacAddress = intent.getStringExtra( REMATCH_P2PADDR_EXTRA );
String dict = intent.getStringExtra( REMATCH_DICT_EXTRA );
int lang = intent.getIntExtra( REMATCH_LANG_EXTRA, -1 );
String json = intent.getStringExtra( REMATCH_PREFS_EXTRA );
int bits = intent.getIntExtra( REMATCH_ADDRS_EXTRA, -1 );
CommsConnTypeSet addrs = new CommsConnTypeSet( bits );
Bundle extras = m_rematchExtras;
int bits = extras.getInt( REMATCH_ADDRS_EXTRA, -1 );
final CommsConnTypeSet addrs = new CommsConnTypeSet( bits );
boolean hasSMS = addrs.contains( CommsConnType.COMMS_CONN_SMS );
if ( !hasSMS || null != SMSService.getPhoneInfo( m_activity ) ) {
rematchWithNameAndPerm( gameName, addrs );
} else {
int id = (1 == addrs.size())
? R.string.phone_lookup_rationale_drop
: R.string.phone_lookup_rationale_others;
String msg = getString( R.string.phone_lookup_rationale )
+ "\n\n" + getString( id );
Perms23.tryGetPerms( this, Perm.READ_PHONE_STATE, msg,
Action.ASKED_PHONE_STATE, this,
gameName, addrs );
}
}
}
private void rematchWithNameAndPerm( boolean granted, Object[] params )
{
CommsConnTypeSet addrs = (CommsConnTypeSet)params[1];
if ( !granted ) {
addrs.remove( CommsConnType.COMMS_CONN_SMS );
m_rematchExtras.remove( REMATCH_PHONE_EXTRA );
}
if ( 0 < addrs.size() ) {
rematchWithNameAndPerm( (String)params[0], addrs );
}
}
private void rematchWithNameAndPerm( String gameName, CommsConnTypeSet addrs )
{
if ( null != gameName && 0 < gameName.length() ) {
Bundle extras = m_rematchExtras;
long srcRowID = extras.getLong( REMATCH_ROWID_EXTRA, DBUtils.ROWID_NOTFOUND );
boolean solo = extras.getBoolean( REMATCH_IS_SOLO, true );
long newid;
if ( null == btAddr && null == phone && null == relayID
&& null == p2pMacAddress ) {
if ( solo ) {
newid = GameUtils.dupeGame( m_activity, srcRowID );
if ( DBUtils.ROWID_NOTFOUND != newid ) {
DBUtils.setName( m_activity, newid, gameName );
}
} else {
String btAddr = extras.getString( REMATCH_BTADDR_EXTRA );
String phone = extras.getString( REMATCH_PHONE_EXTRA );
String relayID = extras.getString( REMATCH_RELAYID_EXTRA );
String p2pMacAddress = extras.getString( REMATCH_P2PADDR_EXTRA );
String dict = extras.getString( REMATCH_DICT_EXTRA );
int lang = extras.getInt( REMATCH_LANG_EXTRA, -1 );
String json = extras.getString( REMATCH_PREFS_EXTRA );
long groupID = DBUtils.getGroupForGame( m_activity, srcRowID );
newid = GameUtils.makeNewMultiGame( m_activity, groupID, dict,
lang, json, addrs, gameName );
@ -2184,7 +2237,7 @@ public class GamesListDelegate extends ListDelegateBase
}
launchGame( newid );
}
m_rematchIntent = null;
m_rematchExtras = null;
}
private void tryAlert( Intent intent )
@ -2430,7 +2483,7 @@ public class GamesListDelegate extends ListDelegateBase
GameSummary summary = (GameSummary)params[1];
final long rowid = (Long)params[0];
if ( summary.conTypes.contains( CommsAddrRec.CommsConnType.COMMS_CONN_RELAY )
if ( summary.conTypes.contains( CommsConnType.COMMS_CONN_RELAY )
&& summary.roomName.length() == 0 ) {
Assert.fail();
} else {
@ -2653,22 +2706,28 @@ public class GamesListDelegate extends ListDelegateBase
intent = makeSelfIntent( context );
intent.putExtra( REMATCH_ROWID_EXTRA, rowid );
intent.putExtra( REMATCH_DICT_EXTRA, gi.dictName );
boolean isSolo = gi.serverRole == CurGameInfo.DeviceRole.SERVER_STANDALONE;
intent.putExtra( REMATCH_IS_SOLO, isSolo );
intent.putExtra( REMATCH_LANG_EXTRA, gi.dictLang );
intent.putExtra( REMATCH_PREFS_EXTRA, gi.getJSONData() );
intent.putExtra( REMATCH_NEWNAME_EXTRA, newName );
if ( null != addrTypes ) {
intent.putExtra( REMATCH_ADDRS_EXTRA, addrTypes.toInt() ); // here
intent.putExtra( REMATCH_ADDRS_EXTRA, addrTypes.toInt() );
if ( null != btAddr ) {
Assert.assertTrue( addrTypes.contains( CommsConnType.COMMS_CONN_BT ) );
intent.putExtra( REMATCH_BTADDR_EXTRA, btAddr );
}
if ( null != phone ) {
Assert.assertTrue( addrTypes.contains( CommsConnType.COMMS_CONN_SMS ) );
intent.putExtra( REMATCH_PHONE_EXTRA, phone );
}
if ( null != relayID ) {
Assert.assertTrue( addrTypes.contains( CommsConnType.COMMS_CONN_RELAY ) );
intent.putExtra( REMATCH_RELAYID_EXTRA, relayID );
}
if ( null != p2pMacAddress ) {
Assert.assertTrue( addrTypes.contains( CommsConnType.COMMS_CONN_P2P ) );
intent.putExtra( REMATCH_P2PADDR_EXTRA, p2pMacAddress );
}
}

View file

@ -23,7 +23,6 @@ package org.eehouse.android.xw4;
import android.os.Bundle;
public class GamesListFrag extends XWFragment {
private static final String TAG = GamesListFrag.class.getSimpleName();
public GamesListFrag() {}

View file

@ -50,6 +50,8 @@ abstract class InviteDelegate extends ListDelegateBase
private static final String TAG = InviteDelegate.class.getSimpleName();
protected interface InviterItem {
boolean equals(InviterItem item);
String getDev(); // the string that identifies this item in results
}
protected static class TwoStringPair implements InviterItem {
@ -68,11 +70,22 @@ abstract class InviteDelegate extends ListDelegateBase
}
return pairs;
}
}
// Children implement ...
abstract void onChildAdded( View child, InviterItem item );
abstract void listSelected( InviterItem[] selected, String[] devs );
public String getDev() { return str1; }
public boolean equals( InviterItem item )
{
boolean result = false;
if ( null != item ) {
TwoStringPair pair = (TwoStringPair)item;
result = str1.equals( pair.str1 )
&& ((null == str2 && null == pair.str2)
|| str2.equals( pair.str2 ) );
DbgUtils.logd( TAG, "%s.equals(%s) => %b", str1, pair.str1, result );
}
return result;
}
}
public static final String DEVS = "DEVS";
public static final String COUNTS = "COUNTS";
@ -82,17 +95,13 @@ abstract class InviteDelegate extends ListDelegateBase
protected int m_nMissing;
protected String m_lastDev;
protected Button m_inviteButton;
protected Button m_rescanButton;
protected Button m_clearButton;
private Activity m_activity;
private ListView m_lv;
private TextView m_ev;
private boolean m_showAddrs;
private InviteItemsAdapter m_adapter;
protected Map<InviterItem, Integer> m_counts;
protected Set<Integer> m_checked;
protected Set<InviterItem> m_checked;
private boolean m_setChecked;
// private LinearLayout[] m_items;
public InviteDelegate( Delegator delegator, Bundle savedInstanceState )
{
@ -102,7 +111,7 @@ abstract class InviteDelegate extends ListDelegateBase
m_nMissing = intent.getIntExtra( INTENT_KEY_NMISSING, -1 );
m_lastDev = intent.getStringExtra( INTENT_KEY_LASTDEV );
m_counts = new HashMap<InviterItem, Integer>();
m_checked = new HashSet<Integer>();
m_checked = new HashSet<InviterItem>();
}
protected void init( String descTxt, int emptyMsgId )
@ -124,6 +133,9 @@ abstract class InviteDelegate extends ListDelegateBase
tryEnable();
}
// Children implement ...
abstract void onChildAdded( View child, InviterItem item );
// Subclasses are meant to call this
protected void addButtonBar( int buttonBarId, int[] buttonBarItemIds )
{
@ -150,11 +162,18 @@ abstract class InviteDelegate extends ListDelegateBase
protected void updateListAdapter( int itemId, InviterItem[] items )
{
// m_items = items;
updateChecked( items );
m_adapter = new InviteItemsAdapter( itemId, items );
setListAdapter( m_adapter );
}
protected void listSelected( InviterItem[] selected, String[] devs )
{
for ( int ii = 0; ii < selected.length; ++ii ) {
devs[ii] = selected[ii].getDev();
}
}
protected void onBarButtonClicked( int id )
{
Assert.fail(); // subclass must implement
@ -192,9 +211,8 @@ abstract class InviteDelegate extends ListDelegateBase
{
int ii = 0;
InviterItem[] result = new InviterItem[m_checked.size()];
InviterItem[] src = getAdapter().getItems();
for ( int checked : m_checked ) {
result[ii++] = src[checked];
for ( InviterItem checked : m_checked ) {
result[ii++] = checked;
}
return result;
}
@ -223,33 +241,43 @@ abstract class InviteDelegate extends ListDelegateBase
m_inviteButton.setEnabled( count > 0 && count <= m_nMissing );
}
final Set<Integer> getChecked() { return m_checked; }
final Set<InviterItem> getChecked() { return m_checked; }
protected void clearChecked() { m_checked.clear(); }
// protected void scan() {}
// Figure which previously-checked items belong in the new set.
private void updateChecked( InviterItem[] newItems )
{
Set<InviterItem> old = new HashSet<InviterItem>();
old.addAll( m_checked );
m_checked.clear();
for ( Iterator<InviterItem> iter = old.iterator(); iter.hasNext(); ) {
InviterItem oldItem = iter.next();
for ( InviterItem item : newItems ) {
if ( item.equals( oldItem ) ) {
m_checked.add( item );
break;
}
}
}
}
// callbacks made by InviteItemsAdapter
protected void onItemChecked( int index, boolean checked )
protected void onItemChecked( InviterItem item, boolean checked )
{
DbgUtils.logd( TAG, "onItemChecked(%d, %b)", index, checked );
if ( checked ) {
m_checked.add( index );
m_checked.add( item );
} else {
m_checked.remove( index );
m_checked.remove( item );
}
}
protected InviteItemsAdapter getAdapter()
private InviteItemsAdapter getAdapter()
{
return m_adapter;
}
private Integer[] makeCheckedArray()
{
return m_checked.toArray( new Integer[m_checked.size()] );
}
private class InviteItemsAdapter extends XWListAdapter {
private InviterItem[] m_items;
private int m_itemId;
@ -318,26 +346,25 @@ abstract class InviteDelegate extends ListDelegateBase
m_setChecked = false;
}
if ( isChecked ) {
m_checked.add( position );
m_checked.add( item );
} else {
m_checked.remove( position );
m_checked.remove( item );
// // User's now making changes; don't check new views
// m_setChecked = false;
}
onItemChecked( position, isChecked );
onItemChecked( item, isChecked );
tryEnable();
}
};
box.setOnCheckedChangeListener( listener );
if ( m_setChecked || m_checked.contains( position ) ) {
if ( m_setChecked || m_checked.contains( item ) ) {
box.setChecked( true );
} else if ( null != m_lastDev && m_lastDev.equals( item ) ) {
} else if ( null != m_lastDev && m_lastDev.equals(item.getDev()) ) {
m_lastDev = null;
box.setChecked( true );
}
// m_items[position] = layout;
return layout;
}

View file

@ -26,7 +26,6 @@ import android.util.AttributeSet;
import org.eehouse.android.xw4.loc.LocUtils;
public class LangListPreference extends XWListPreference {
private static final String TAG = LangListPreference.class.getSimpleName();
private Context m_context;
public LangListPreference( Context context, AttributeSet attrs )

View file

@ -26,7 +26,6 @@ import android.widget.ListAdapter;
import android.widget.ListView;
public class ListDelegateBase extends DelegateBase {
private static final String TAG = ListDelegateBase.class.getSimpleName();
private Activity m_activity;
private Delegator m_delegator;

View file

@ -85,6 +85,7 @@ public class MultiService {
SMS_SEND_OK,
SMS_SEND_FAILED,
SMS_SEND_FAILED_NORADIO,
SMS_SEND_FAILED_NOPERMISSION,
BT_GAME_CREATED,
BT_ERR_COUNT,

View file

@ -524,6 +524,7 @@ public class NetLaunchInfo {
public void addSMSInfo( Context context )
{
SMSService.SMSPhoneInfo pi = SMSService.getPhoneInfo( context );
if ( null != pi ) {
phone = pi.number;
isGSM = pi.isGSM;
@ -531,6 +532,7 @@ public class NetLaunchInfo {
m_addrs.add( CommsConnType.COMMS_CONN_SMS );
}
}
public void addP2PInfo( Context context )
{

View file

@ -28,7 +28,6 @@ import android.widget.ScrollView;
import android.widget.TextView;
public class NotAgainView extends ScrollView {
private static final String TAG = NotAgainView.class.getSimpleName();
public NotAgainView( Context cx, AttributeSet as ) {
super( cx, as );

View file

@ -20,6 +20,8 @@
package org.eehouse.android.xw4;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.pm.PackageManager;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
@ -30,6 +32,10 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.eehouse.android.xw4.DlgDelegate.Action;
import org.eehouse.android.xw4.DlgDelegate.DlgClickNotify;
import org.eehouse.android.xw4.loc.LocUtils;
import junit.framework.Assert;
public class Perms23 {
@ -61,7 +67,7 @@ public class Perms23 {
void onPermissionResult( Map<Perm, Boolean> perms );
}
public interface OnShowRationale {
void onShouldShowRationale( Set<Perms23.Perm> perms );
void onShouldShowRationale( Set<Perm> perms );
}
public static class Builder {
@ -105,11 +111,10 @@ public class Perms23 {
boolean haveIt = PackageManager.PERMISSION_GRANTED
== ContextCompat.checkSelfPermission( activity, permStr );
// For research: ask the OS if we should be printing a rationale
if ( !haveIt ) {
askStrings.add( permStr );
if ( ActivityCompat
if ( null != m_onShow && ActivityCompat
.shouldShowRequestPermissionRationale( activity,
permStr ) ) {
needShow.add( perm );
@ -119,9 +124,7 @@ public class Perms23 {
haveAll = haveAll && haveIt;
}
if ( 0 < needShow.size() && null != m_onShow ) {
m_onShow.onShouldShowRationale( needShow );
} else if ( haveAll ) {
if ( haveAll ) {
if ( null != cbck ) {
Map<Perm, Boolean> map = new HashMap<Perm, Boolean>();
for ( Perm perm : m_perms ) {
@ -129,19 +132,117 @@ public class Perms23 {
}
cbck.onPermissionResult( map );
}
} else if ( 0 < needShow.size() && null != m_onShow ) {
// DbgUtils.logd( TAG, "calling onShouldShowRationale()" );
m_onShow.onShouldShowRationale( needShow );
} else {
String[] permsArray = askStrings.toArray( new String[askStrings.size()] );
int code = register( cbck );
// DbgUtils.logd( TAG, "calling requestPermissions on %s",
// activity.getClass().getSimpleName() );
ActivityCompat.requestPermissions( activity, permsArray, code );
}
DbgUtils.logd( TAG, "asyncQuery(%s) DONE", m_perms.toString() );
}
}
private static class QueryInfo {
private Action m_action;
private Perm m_perm;
private DelegateBase m_delegate;
private DlgClickNotify m_cbck;
private String m_rationaleMsg;
private Object[] m_params;
public QueryInfo( DelegateBase delegate, Action action,
Perm perm, String msg,
DlgClickNotify cbck, Object[] params ) {
m_delegate = delegate;
m_action = action;
m_perm = perm;
m_rationaleMsg = msg;
m_cbck = cbck;
m_params = params;
}
private void doIt( boolean showRationale )
{
Builder builder = new Builder( m_perm );
if ( showRationale && null != m_rationaleMsg ) {
builder.setOnShowRationale( new OnShowRationale() {
public void onShouldShowRationale( Set<Perm> perms ) {
m_delegate.makeConfirmThenBuilder( m_rationaleMsg,
Action.PERMS_QUERY )
.setTitle( R.string.perms_rationale_title )
.setPosButton( R.string.button_ask_again )
.setNegButton( R.string.button_skip )
.setParams( QueryInfo.this )
.show();
}
} );
}
builder.asyncQuery( m_delegate.getActivity(), new PermCbck() {
public void onPermissionResult( Map<Perm, Boolean> perms ) {
if ( Action.SKIP_CALLBACK != m_action ) {
if ( perms.get( m_perm ) ) {
m_cbck.onPosButton( m_action, m_params );
} else {
m_cbck.onNegButton( m_action, m_params );
}
}
}
} );
}
// Post this in case we're called from inside dialog dismiss
// code. Better to unwind the stack...
private void handleButton( final boolean positive )
{
m_delegate.post( new Runnable() {
public void run() {
if ( positive ) {
doIt( false );
} else {
m_cbck.onNegButton( m_action, m_params );
}
}
} );
}
}
/**
* Request permissions, giving rationale once, then call with action and
* either positive or negative, the former if permission granted.
*/
public static void tryGetPerms( DelegateBase delegate, Perm perm, int rationaleId,
final Action action, final DlgClickNotify cbck,
Object... params )
{
// DbgUtils.logd( TAG, "tryGetPerms(%s)", perm.toString() );
Context context = XWApp.getContext();
String msg = LocUtils.getString( context, rationaleId );
tryGetPerms( delegate, perm, msg, action, cbck, params );
}
public static void tryGetPerms( DelegateBase delegate, Perm perm,
String rationaleMsg, final Action action,
final DlgClickNotify cbck, Object... params )
{
// DbgUtils.logd( TAG, "tryGetPerms(%s)", perm.toString() );
new QueryInfo( delegate, action, perm, rationaleMsg, cbck, params )
.doIt( true );
}
public static void onGotPermsAction( boolean positive, Object[] params )
{
// DbgUtils.logd( TAG, "onGotPermsAction(button=%d)", button );
QueryInfo info = (QueryInfo)params[0];
info.handleButton( positive );
}
private static Map<Integer, PermCbck> s_map = new HashMap<Integer, PermCbck>();
public static void gotPermissionResult( int code, String[] perms, int[] granteds )
{
// DbgUtils.logd( TAG, "gotPermissionResult(%s)", perms.toString() );
PermCbck cbck = s_map.remove( code );
if ( null != cbck ) {
Map<Perm, Boolean> result = new HashMap<Perm, Boolean>();
@ -165,9 +266,12 @@ public class Perms23 {
return result;
}
private static int s_nextRecord;
// This is probably overkill as the OS only allows one permission request
// at a time
private static int s_nextRecord = 0;
private static int register( PermCbck cbck )
{
Assert.assertTrue( !BuildConfig.DEBUG || 0 == s_map.size() );
DbgUtils.assertOnUIThread();
int code = ++s_nextRecord;
s_map.put( code, cbck );

View file

@ -242,10 +242,8 @@ public class PrefsDelegate extends DelegateBase
}
@Override
public void dlgButtonClicked( Action action, int button, Object[] params )
public void onPosButton( Action action, Object[] params )
{
boolean handled = AlertDialog.BUTTON_POSITIVE == button;
if ( handled ) {
switch ( action ) {
case ENABLE_SMS_DO:
XWPrefs.setSMSEnabled( m_activity, true );
@ -256,12 +254,7 @@ public class PrefsDelegate extends DelegateBase
RelayCheckBoxPreference.setChecked();
break;
default:
handled = false;
}
}
if ( !handled ) {
super.dlgButtonClicked( action, button, params );
super.onPosButton( action, params );
}
}

View file

@ -27,7 +27,6 @@ import org.eehouse.android.xw4.DlgDelegate.Action;
import org.eehouse.android.xw4.loc.LocUtils;
public class RelayCheckBoxPreference extends ConfirmingCheckBoxPreference {
private static final String TAG = RelayCheckBoxPreference.class.getSimpleName();
private static ConfirmingCheckBoxPreference s_this = null;
public RelayCheckBoxPreference( Context context, AttributeSet attrs )

View file

@ -23,7 +23,6 @@ package org.eehouse.android.xw4;
import android.os.Bundle;
public class RelayInviteActivity extends InviteActivity {
private static final String TAG = RelayInviteActivity.class.getSimpleName();
private RelayInviteDelegate m_dlgt;
@Override

View file

@ -207,12 +207,6 @@ public class RelayInviteDelegate extends InviteDelegate {
Assert.fail();
}
@Override
public void listSelected( InviterItem[] selected, String[] devsP )
{
Assert.fail();
}
// We want to present user with list of previous opponents and devices. We
// can easily get list of relayIDs. The relay, if reachable, can convert
// that to a (likely shorter) list of devices. Then for each deviceID,
@ -284,10 +278,8 @@ public class RelayInviteDelegate extends InviteDelegate {
// DlgDelegate.DlgClickNotify interface
@Override
public void dlgButtonClicked( Action action, int which, Object[] params )
public void onPosButton( Action action, Object[] params )
{
switch( which ) {
case AlertDialog.BUTTON_POSITIVE:
switch( action ) {
case CLEAR_ACTION:
clearSelectedImpl();
@ -295,17 +287,21 @@ public class RelayInviteDelegate extends InviteDelegate {
case USE_IMMOBILE_ACTION:
m_immobileConfirmed = true;
break;
}
default:
super.onPosButton( action, params );
break;
case DlgDelegate.DISMISS_BUTTON:
}
}
@Override
public void onDismissed( Action action, Object[] params )
{
if ( Action.USE_IMMOBILE_ACTION == action && m_immobileConfirmed ) {
makeConfirmThenBuilder( R.string.warn_unlimited,
Action.POST_WARNING_ACTION )
.setPosButton( R.string.button_yes )
.show();
}
break;
}
}
// private int countChecks()
@ -448,6 +444,14 @@ public class RelayInviteDelegate extends InviteDelegate {
m_nPlayers = 1;
m_opponent = opponent;
}
public String getDev() { return m_devID; }
public boolean equals( InviterItem item )
{
return item != null
&& ((DevIDRec)item).m_devID == m_devID;
}
}
// private class RelayDevsAdapter extends XWListAdapter {

View file

@ -28,7 +28,6 @@ import android.content.Intent;
import android.os.SystemClock;
public class RelayReceiver extends BroadcastReceiver {
private static final String TAG = RelayReceiver.class.getSimpleName();
@Override
public void onReceive( Context context, Intent intent )

View file

@ -27,7 +27,6 @@ import java.lang.ref.WeakReference;
import org.eehouse.android.xw4.DlgDelegate.Action;
public class SMSCheckBoxPreference extends ConfirmingCheckBoxPreference {
private static final String TAG = SMSCheckBoxPreference.class.getSimpleName();
private static WeakReference<ConfirmingCheckBoxPreference> s_this = null;
public SMSCheckBoxPreference( Context context, AttributeSet attrs )

View file

@ -23,7 +23,6 @@ package org.eehouse.android.xw4;
import android.os.Bundle;
public class SMSInviteActivity extends InviteActivity {
private static final String TAG = SMSInviteActivity.class.getSimpleName();
private SMSInviteDelegate m_dlgt;

View file

@ -30,32 +30,27 @@ import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract;
import android.telephony.PhoneNumberUtils;
import android.text.method.DialerKeyListener;
import android.view.View;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.Spinner;
import android.widget.TextView;
import junit.framework.Assert;
import org.eehouse.android.xw4.DBUtils.SentInvitesInfo;
import org.eehouse.android.xw4.DlgDelegate.Action;
import org.eehouse.android.xw4.Perms23.Perm;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.json.JSONObject;
import org.json.JSONException;
public class SMSInviteDelegate extends InviteDelegate
implements View.OnClickListener {
public class SMSInviteDelegate extends InviteDelegate {
private static final String TAG = SMSInviteDelegate.class.getSimpleName();
private static int[] BUTTONIDS = {
R.id.button_add,
@ -63,11 +58,7 @@ public class SMSInviteDelegate extends InviteDelegate
R.id.button_clear,
};
private static final String SAVE_NAME = "SAVE_NAME";
private static final String SAVE_NUMBER = "SAVE_NUMBER";
private ArrayList<PhoneRec> m_phoneRecs;
private ImageButton m_addButton;
private boolean m_immobileConfirmed;
private Activity m_activity;
@ -98,12 +89,10 @@ public class SMSInviteDelegate extends InviteDelegate
super.init( msg, R.string.empty_sms_inviter );
addButtonBar( R.layout.sms_buttons, BUTTONIDS );
// getBundledData( savedInstanceState );
getSavedState();
rebuildList( true );
askContactsPermission( true );
askContactsPermission();
}
@Override
@ -178,15 +167,6 @@ public class SMSInviteDelegate extends InviteDelegate
return dialog;
}
@Override
protected void listSelected( InviterItem[] selected, String[] devs )
{
for ( int ii = 0; ii < selected.length; ++ii ) {
PhoneRec rec = (PhoneRec)selected[ii];
devs[ii] = rec.m_phone;
}
}
@Override
protected void onChildAdded( View child, InviterItem data )
{
@ -194,36 +174,47 @@ public class SMSInviteDelegate extends InviteDelegate
((TwoStrsItem)child).setStrings( rec.m_name, rec.m_phone );
}
@Override
protected void tryEnable()
{
super.tryEnable();
Button button = (Button)findViewById( R.id.button_clear );
if ( null != button ) { // may not be there yet
button.setEnabled( 0 < getChecked().size() );
}
}
// DlgDelegate.DlgClickNotify interface
@Override
public void dlgButtonClicked( Action action, int which,
final Object[] params )
public void onPosButton( Action action, Object[] params )
{
boolean isPositive = AlertDialog.BUTTON_POSITIVE == which;
DbgUtils.logd( TAG, "dlgButtonClicked(%s,pos:%b)",
action.toString(), isPositive );
switch ( action ) {
case RETRY_CONTACTS_ACTION:
askContactsPermission( false );
break;
case CLEAR_ACTION:
if ( isPositive) {
clearSelectedImpl();
}
break;
case POST_WARNING_ACTION:
DbgUtils.printStack( TAG );
if ( isPositive ) { // ???
m_phoneRecs.add( new PhoneRec( (String)params[1],
(String)params[0] ) );
saveAndRebuild();
}
break;
case USE_IMMOBILE_ACTION:
if ( isPositive ) {
m_immobileConfirmed = true;
} else if ( m_immobileConfirmed ) {
break;
case POST_WARNING_ACTION:
PhoneRec rec = new PhoneRec( (String)params[1],
(String)params[0] );
m_phoneRecs.add( rec );
clearChecked();
onItemChecked( rec, true );
saveAndRebuild();
break;
default:
super.onPosButton( action, params );
}
}
@Override
public void onNegButton( Action action, final Object[] params )
{
switch ( action ) {
case USE_IMMOBILE_ACTION:
if ( m_immobileConfirmed ) {
// Putting up a new alert from inside another's handler
// confuses things. So post instead.
post( new Runnable() {
@ -238,6 +229,8 @@ public class SMSInviteDelegate extends InviteDelegate
} );
}
break;
default:
super.onNegButton( action, params );
}
}
@ -265,23 +258,22 @@ public class SMSInviteDelegate extends InviteDelegate
int type = cursor.getInt( cursor.
getColumnIndex( Phone.TYPE ) );
DlgDelegate.ConfirmThenBuilder builder;
if ( Phone.TYPE_MOBILE == type ) {
makeConfirmThenBuilder( R.string.warn_unlimited,
Action.POST_WARNING_ACTION )
.setPosButton( R.string.button_yes )
.setParams( number, name )
.show();
builder = makeConfirmThenBuilder( R.string.warn_unlimited,
Action.POST_WARNING_ACTION );
} else {
m_immobileConfirmed = false;
String msg = getString( R.string.warn_nomobile_fmt,
number, name );
makeConfirmThenBuilder( msg, Action.USE_IMMOBILE_ACTION )
.setPosButton( R.string.button_yes )
builder = makeConfirmThenBuilder( msg, Action.USE_IMMOBILE_ACTION );
}
builder.setPosButton( R.string.button_yes )
.setParams( number, name )
.show();
}
}
}
} // addPhoneNumbers
private void rebuildList( boolean checkIfAll )
@ -291,13 +283,6 @@ public class SMSInviteDelegate extends InviteDelegate
return rec1.m_name.compareTo(rec2.m_name);
}
});
// String[] phones = new String[m_phoneRecs.size()];
// String[] names = new String[m_phoneRecs.size()];
// for ( int ii = 0; ii < m_phoneRecs.size(); ++ii ) {
// PhoneRec rec = m_phoneRecs.get( ii );
// phones[ii] = rec.m_phone;
// names[ii] = rec.m_name;
// }
updateListAdapter( m_phoneRecs.toArray( new PhoneRec[m_phoneRecs.size()] ) );
tryEnable();
@ -335,31 +320,24 @@ public class SMSInviteDelegate extends InviteDelegate
private void clearSelectedImpl()
{
Set<Integer> checked = getChecked();
for ( int ii = m_phoneRecs.size() - 1; ii >= 0; --ii ) {
if ( checked.contains( ii ) ) {
m_phoneRecs.remove( ii );
Set<InviterItem> checked = getChecked();
Iterator<PhoneRec> iter = m_phoneRecs.iterator();
for ( ; iter.hasNext(); ) {
if ( checked.contains( iter.next() ) ) {
iter.remove();
}
}
clearChecked();
saveAndRebuild();
}
private void askContactsPermission( boolean showRationale )
private void askContactsPermission()
{
Perms23.Builder builder = new Perms23.Builder( Perms23.Perm.READ_CONTACTS );
if ( showRationale ) {
builder.setOnShowRationale( new Perms23.OnShowRationale() {
@Override
public void onShouldShowRationale( Set<Perms23.Perm> perms )
{
makeOkOnlyBuilder( R.string.contacts_rationale )
.setAction( Action.RETRY_CONTACTS_ACTION )
.show();
}
} );
}
builder.asyncQuery( m_activity );
// We want to ask, and to give the rationale, but behave the same
// regardless of the answers given. So SKIP_CALLBACK.
Perms23.tryGetPerms( this, Perm.READ_CONTACTS,
R.string.contacts_rationale,
Action.SKIP_CALLBACK, this );
}
private class PhoneRec implements InviterItem {
@ -371,6 +349,19 @@ public class SMSInviteDelegate extends InviteDelegate
this( null, phone );
}
public String getDev() { return m_phone; }
public boolean equals( InviterItem item )
{
boolean result = false;
if ( null != item && item instanceof PhoneRec ) {
PhoneRec rec = (PhoneRec)item;
result = m_name.equals(rec.m_name)
&& PhoneNumberUtils.compare( m_phone, rec.m_phone );
}
return result;
}
private PhoneRec( String name, String phone )
{
m_phone = phone;

View file

@ -112,31 +112,34 @@ public class SMSService extends XWService {
public String number;
public boolean isGSM;
}
private static SMSPhoneInfo s_phoneInfo;
private static SMSPhoneInfo s_phoneInfo;
public static SMSPhoneInfo getPhoneInfo( Context context )
{
if ( null == s_phoneInfo ) {
try {
String number = null;
boolean isGSM = false;
boolean isPhone = false;
TelephonyManager mgr = (TelephonyManager)
context.getSystemService(Context.TELEPHONY_SERVICE);
if ( null != mgr ) {
number = mgr.getLine1Number();
number = mgr.getLine1Number(); // needs permission
int type = mgr.getPhoneType();
isGSM = TelephonyManager.PHONE_TYPE_GSM == type;
isPhone = true;
}
String radio = XWPrefs.getPrefsString( context, R.string.key_force_radio );
String radio =
XWPrefs.getPrefsString( context, R.string.key_force_radio );
int[] ids = { R.string.radio_name_real,
R.string.radio_name_tablet,
R.string.radio_name_gsm,
R.string.radio_name_cdma,
};
int id = R.string.radio_name_real; // default so don't crash before set
// default so don't crash before set
int id = R.string.radio_name_real;
for ( int ii = 0; ii < ids.length; ++ii ) {
if ( radio.equals(context.getString(ids[ii])) ) {
id = ids[ii];
@ -162,6 +165,9 @@ public class SMSService extends XWService {
}
s_phoneInfo = new SMSPhoneInfo( isPhone, number, isGSM );
} catch ( SecurityException se ) {
DbgUtils.loge( TAG, "got SecurityException" );
}
}
return s_phoneInfo;
}
@ -654,7 +660,8 @@ public class SMSService extends XWService {
// Try send-to-self
if ( XWPrefs.getSMSToSelfEnabled( this ) ) {
String myPhone = getPhoneInfo( this ).number;
if ( PhoneNumberUtils.compare( phone, myPhone ) ) {
if ( null != myPhone
&& PhoneNumberUtils.compare( phone, myPhone ) ) {
for ( byte[] fragment : fragments ) {
handleFrom( this, fragment, phone );
}
@ -680,8 +687,7 @@ public class SMSService extends XWService {
} catch ( NullPointerException npe ) {
Assert.fail(); // shouldn't be trying to do this!!!
} catch ( java.lang.SecurityException se ) {
DbgUtils.logd( TAG, "caught SecurityException; "
+ "no SEND_SMS permission?" );
postEvent( MultiEvent.SMS_SEND_FAILED_NOPERMISSION );
} catch ( Exception ee ) {
DbgUtils.logex( TAG, ee );
}
@ -719,11 +725,9 @@ public class SMSService extends XWService {
postEvent( MultiEvent.SMS_SEND_OK );
break;
case SmsManager.RESULT_ERROR_RADIO_OFF:
DbgUtils.showf( SMSService.this, "NO RADIO!!!" );
postEvent( MultiEvent.SMS_SEND_FAILED_NORADIO );
break;
case SmsManager.RESULT_ERROR_NO_SERVICE:
DbgUtils.showf( SMSService.this, "NO SERVICE!!!" );
default:
DbgUtils.logw( TAG, "FAILURE!!!" );
postEvent( MultiEvent.SMS_SEND_FAILED );

View file

@ -22,7 +22,6 @@ package org.eehouse.android.xw4;
import android.os.Bundle;
public class StudyListActivity extends XWActivity {
private static final String TAG = StudyListActivity.class.getSimpleName();
@Override
protected void onCreate( Bundle savedInstanceState )

View file

@ -153,9 +153,8 @@ public class StudyListDelegate extends ListDelegateBase
// DlgDelegate.DlgClickNotify interface
//////////////////////////////////////////////////
@Override
public void dlgButtonClicked( Action action, int which, Object[] params )
public void onPosButton( Action action, Object[] params )
{
if ( AlertDialog.BUTTON_POSITIVE == which ) {
switch ( action ) {
case SL_CLEAR_ACTION:
String[] selWords = getSelWords();
@ -181,7 +180,6 @@ public class StudyListDelegate extends ListDelegateBase
break;
}
}
}
//////////////////////////////////////////////////
// AdapterView.OnItemSelectedListener interface

View file

@ -23,7 +23,6 @@ package org.eehouse.android.xw4;
import android.os.Bundle;
public class StudyListFrag extends XWFragment {
private static final String TAG = StudyListFrag.class.getSimpleName();
public StudyListFrag() {}

View file

@ -27,7 +27,6 @@ import android.graphics.Rect;
import org.eehouse.android.xw4.jni.XwJNI;
public class ThumbCanvas extends BoardCanvas {
private static final String TAG = ThumbCanvas.class.getSimpleName();
public ThumbCanvas( Context context, Bitmap bitmap )
{

View file

@ -28,9 +28,12 @@ import android.widget.HorizontalScrollView;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import junit.framework.Assert;
@ -62,6 +65,7 @@ public class Toolbar implements BoardContainer.SizeChangeListener {
private boolean m_visible;
private Map<Buttons, Object> m_onClickListeners;
private Map<Buttons, Object> m_onLongClickListeners;
private Set<Buttons> m_enabled = new HashSet<Buttons>();
public Toolbar( Activity activity, HasDlgDelegate dlgDlgt )
{
@ -123,7 +127,15 @@ public class Toolbar implements BoardContainer.SizeChangeListener {
if ( null != button ) {
button.setVisibility( enable ? View.VISIBLE : View.GONE );
}
if ( enable ) {
m_enabled.add( index );
} else {
m_enabled.remove( index );
}
}
protected int enabledCount() { return m_enabled.size(); }
// SizeChangeListener
public void sizeChanged( int width, int height, boolean isPortrait )

View file

@ -22,13 +22,13 @@ package org.eehouse.android.xw4;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.LinearLayout;
import android.widget.TextView;
public class TwoStrsItem extends LinearLayout {
private static final String TAG = TwoStrsItem.class.getSimpleName();
public TwoStrsItem( Context cx, AttributeSet as )
{
@ -39,9 +39,14 @@ public class TwoStrsItem extends LinearLayout {
{
TextView tv = (TextView)findViewById( R.id.text1 );
tv.setText( str1 );
tv = (TextView)findViewById( R.id.text2 );
if ( null == str2 ) {
tv.setVisibility( View.GONE );
} else {
tv.setText( str2 );
}
}
public String getStr1()
{

View file

@ -63,6 +63,7 @@ import java.util.Random;
import junit.framework.Assert;
import org.eehouse.android.xw4.Perms23.Perm;
import org.eehouse.android.xw4.jni.CommonPrefs;
import org.eehouse.android.xw4.loc.LocUtils;
@ -77,7 +78,6 @@ public class Utils {
private static Boolean s_isFirstBootThisVersion = null;
private static Boolean s_firstVersion = null;
// private static Boolean s_deviceSupportSMS = null;
private static Boolean s_isFirstBootEver = null;
private static Integer s_appVersion = null;
private static HashMap<String,String> s_phonesHash =
@ -113,9 +113,9 @@ public class Utils {
public static boolean isGSMPhone( Context context )
{
boolean result = false;
if ( Perms23.havePermission( Perms23.Perm.READ_PHONE_STATE ) ) {
if ( Perms23.havePermission( Perm.READ_PHONE_STATE ) ) {
SMSService.SMSPhoneInfo info = SMSService.getPhoneInfo( context );
result = info.isPhone && info.isGSM;
result = null != info && info.isPhone && info.isGSM;
}
DbgUtils.logd( TAG, "isGSMPhone() => %b", result );
return result;
@ -129,20 +129,18 @@ public class Utils {
public static boolean deviceSupportsSMS( Context context )
{
boolean result = false;
if ( Perms23.havePermission( Perms23.Perm.READ_PHONE_STATE ) ) {
if ( Perms23.havePermission( Perm.READ_PHONE_STATE ) ) {
TelephonyManager tm = (TelephonyManager)
context.getSystemService( Context.TELEPHONY_SERVICE );
result = null != tm;
if ( null != tm ) {
int type = tm.getPhoneType();
result = TelephonyManager.PHONE_TYPE_GSM == type;
}
}
DbgUtils.logd( TAG, "deviceSupportsSMS() => %b", result );
return result;
}
public static void smsSupportChanged()
{
// s_deviceSupportSMS = null; // force to check again
}
public static void notImpl( Context context )
{
String text = "Feature coming soon";
@ -283,7 +281,7 @@ public class Utils {
synchronized ( s_phonesHash ) {
if ( s_phonesHash.containsKey( phone ) ) {
name = s_phonesHash.get( phone );
} else if ( Perms23.havePermission( Perms23.Perm.READ_CONTACTS ) ) {
} else if ( Perms23.havePermission( Perm.READ_CONTACTS ) ) {
try {
ContentResolver contentResolver = context
.getContentResolver();
@ -306,7 +304,6 @@ public class Utils {
JSONObject phones = XWPrefs.getSMSPhones( context );
for ( Iterator<String> iter = phones.keys(); iter.hasNext(); ) {
String key = iter.next();
DbgUtils.logd( TAG, "comparing %s, %s", key, phone );
if ( PhoneNumberUtils.compare( key, phone ) ) {
name = phones.optString( key, phone );
s_phonesHash.put( phone, name );

View file

@ -23,7 +23,6 @@ package org.eehouse.android.xw4;
import android.os.Bundle;
public class WiDirInviteActivity extends InviteActivity {
private static final String TAG = WiDirInviteActivity.class.getSimpleName();
private WiDirInviteDelegate m_dlgt;

View file

@ -181,18 +181,20 @@ public class WiDirService extends XWService {
public static void init( Context context )
{
DbgUtils.logd( TAG, "init()" );
try {
ChannelListener listener = new ChannelListener() {
@Override
public void onChannelDisconnected() {
DbgUtils.logd( TAG, "onChannelDisconnected()");
}
};
try {
sChannel = getMgr().initialize( context, Looper.getMainLooper(),
listener );
s_discoverer = new ServiceDiscoverer( sChannel );
sHavePermission = true;
} catch ( SecurityException se ) {
} catch ( NoClassDefFoundError ndf ) { // old os version
sHavePermission = false;
} catch ( SecurityException se ) { // perm not in manifest
sHavePermission = false;
}
}
@ -502,7 +504,7 @@ public class WiDirService extends XWService {
codeStr = "ERROR";
break;
case WifiP2pManager.P2P_UNSUPPORTED:
Assert.fail();
// Assert.fail(); // fires on emulator
codeStr = "UNSUPPORTED";
break;
case WifiP2pManager.BUSY:

View file

@ -131,6 +131,7 @@ public class XWActivity extends FragmentActivity implements Delegator {
public void onRequestPermissionsResult(int requestCode, String perms[], int[] rslts )
{
Perms23.gotPermissionResult( requestCode, perms, rslts );
super.onRequestPermissionsResult( requestCode, perms, rslts );
}
@Override

View file

@ -35,7 +35,6 @@ import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnTypeSet;
import org.eehouse.android.xw4.loc.LocUtils;
public class XWConnAddrPreference extends DialogPreference {
private static final String TAG = XWConnAddrPreference.class.getSimpleName();
private Context m_context;
private ConnViaViewLayout m_view;
@ -112,7 +111,7 @@ public class XWConnAddrPreference extends DialogPreference {
@Override
public void onClick( DialogInterface dialog, int which )
{
if ( AlertDialog.BUTTON_POSITIVE == which ) {
if ( AlertDialog.BUTTON_POSITIVE == which && null != m_view ) {
CommsConnTypeSet curSet = m_view.getTypes();
XWPrefs.setAddrTypes( m_context, curSet );
setSummary( curSet.toString( m_context, true ) );

View file

@ -25,7 +25,6 @@ import android.preference.EditTextPreference;
import android.util.AttributeSet;
public class XWDevIDPreference extends EditTextPreference {
private static final String TAG = XWDevIDPreference.class.getSimpleName();
private Context m_context;
public XWDevIDPreference( Context context, AttributeSet attrs )

View file

@ -25,7 +25,6 @@ import android.preference.EditTextPreference;
import android.util.AttributeSet;
public class XWEditTextPreference extends EditTextPreference {
private static final String TAG = XWEditTextPreference.class.getSimpleName();
public XWEditTextPreference( Context context, AttributeSet attrs )
{

View file

@ -65,6 +65,7 @@ abstract class XWFragment extends Fragment implements Delegator {
@Override
public void onSaveInstanceState( Bundle outState )
{
DbgUtils.logd( TAG, "%s.onCreate() called", getClass().getSimpleName() );
super.onSaveInstanceState( outState );
Assert.assertNotNull( m_parentName );
outState.putString( PARENT_NAME, m_parentName );
@ -72,7 +73,7 @@ abstract class XWFragment extends Fragment implements Delegator {
protected void onCreate( DelegateBase dlgt, Bundle sis )
{
DbgUtils.logd( TAG, "onCreate() called" );
DbgUtils.logd( TAG, "%s.onCreate() called", getClass().getSimpleName() );
super.onCreate( sis );
if ( null != sis ) {
m_parentName = sis.getString( PARENT_NAME );
@ -95,14 +96,14 @@ abstract class XWFragment extends Fragment implements Delegator {
public View onCreateView( LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState )
{
DbgUtils.logd( TAG, "onCreateView() called" );
DbgUtils.logd( TAG, "%s.onCreateView() called", getClass().getSimpleName() );
return m_dlgt.inflateView( inflater, container );
}
@Override
public void onActivityCreated( Bundle savedInstanceState )
{
DbgUtils.logd( TAG, "onActivityCreated() called" );
DbgUtils.logd( TAG, "%s.onActivityCreated() called", getClass().getSimpleName() );
m_dlgt.init( savedInstanceState );
super.onActivityCreated( savedInstanceState );
if ( m_hasOptionsMenu ) {
@ -113,7 +114,7 @@ abstract class XWFragment extends Fragment implements Delegator {
@Override
public void onPause()
{
DbgUtils.logd( TAG, "onPause() called" );
DbgUtils.logd( TAG, "%s.onPause() called", getClass().getSimpleName() );
m_dlgt.onPause();
super.onPause();
}
@ -121,7 +122,7 @@ abstract class XWFragment extends Fragment implements Delegator {
@Override
public void onResume()
{
DbgUtils.logd( TAG, "onResume() called" );
DbgUtils.logd( TAG, "%s.onResume() called", getClass().getSimpleName() );
super.onResume();
m_dlgt.onResume();
}
@ -129,7 +130,7 @@ abstract class XWFragment extends Fragment implements Delegator {
@Override
public void onStart()
{
DbgUtils.logd( TAG, "onStart() called" );
DbgUtils.logd( TAG, "%s.onStart() called", getClass().getSimpleName() );
super.onStart();
m_dlgt.onStart();
}
@ -137,7 +138,7 @@ abstract class XWFragment extends Fragment implements Delegator {
@Override
public void onStop()
{
DbgUtils.logd( TAG, "onStop() called" );
DbgUtils.logd( TAG, "%s.onStop() called", getClass().getSimpleName() );
m_dlgt.onStop();
super.onStop();
}
@ -145,7 +146,7 @@ abstract class XWFragment extends Fragment implements Delegator {
@Override
public void onDestroy()
{
DbgUtils.logd( TAG, "onDestroy() called" );
DbgUtils.logd( TAG, "%s.onDestroy() called", getClass().getSimpleName() );
m_dlgt.onDestroy();
super.onDestroy();
}
@ -153,7 +154,7 @@ abstract class XWFragment extends Fragment implements Delegator {
@Override
public void onActivityResult( int requestCode, int resultCode, Intent data )
{
DbgUtils.logd( TAG, "onActivityResult() called" );
DbgUtils.logd( TAG, "%s.onActivityResult() called", getClass().getSimpleName() );
m_dlgt.onActivityResult( RequestCode.values()[requestCode],
resultCode, data );
}

View file

@ -27,7 +27,6 @@ import android.util.AttributeSet;
import org.eehouse.android.xw4.loc.LocUtils;
public class XWListPreference extends ListPreference {
private static final String TAG = XWListPreference.class.getSimpleName();
protected Context m_context;
public XWListPreference( Context context, AttributeSet attrs )

View file

@ -26,7 +26,6 @@ import android.util.AttributeSet;
import org.eehouse.android.xw4.loc.LocUtils;
public class XWSumListPreference extends XWListPreference {
private static final String TAG = XWSumListPreference.class.getSimpleName();
private static final int[] s_ADDROWS = {
R.string.game_summary_field_npackets,

View file

@ -26,7 +26,6 @@ import android.util.AttributeSet;
import org.eehouse.android.xw4.loc.LocUtils;
public class XWThumbListPreference extends XWListPreference {
private static final String TAG = XWThumbListPreference.class.getSimpleName();
private Context m_context;
public XWThumbListPreference( Context context, AttributeSet attrs )

View file

@ -32,7 +32,6 @@ import org.eehouse.android.xw4.XWPrefs;
import org.eehouse.android.xw4.loc.LocUtils;
public class CommonPrefs extends XWPrefs {
private static final String TAG = CommonPrefs.class.getSimpleName();
public static final int COLOR_TILE_BACK = 0;
public static final int COLOR_NOTILE = 1;
public static final int COLOR_FOCUS = 2;

View file

@ -217,7 +217,8 @@ public class CommsAddrRec {
public CommsAddrRec( CommsConnTypeSet types )
{
conTypes = types;
this();
conTypes.addAll( types );
}
public CommsAddrRec( String host, int port )
@ -359,8 +360,11 @@ public class CommsAddrRec {
break;
case COMMS_CONN_SMS:
SMSService.SMSPhoneInfo pi = SMSService.getPhoneInfo( context );
// Do we have phone permission? If not, shouldn't be set at all!
if ( null != pi ) {
sms_phone = pi.number;
sms_port = 3; // fix comms already...
}
break;
case COMMS_CONN_P2P:
p2p_addr = WiDirService.getMyMacAddress( context );

View file

@ -1,7 +1,7 @@
/* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/*
* Copyright 2009 - 2012 by Eric House (xwords@eehouse.org). All
* rights reserved.
* Copyright 2009 - 2017 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
@ -166,7 +166,7 @@ public class JNIThread extends Thread {
m_queue = new LinkedBlockingQueue<QueueElem>();
}
public JNIThread configure( Context context, SyncedDraw drawer,
public boolean configure( Context context, SyncedDraw drawer,
UtilCtxtImpl utils,
TransportProcs.TPMsgHandler xportHandler,
Handler handler )
@ -190,8 +190,9 @@ public class JNIThread extends Thread {
String[] dictNames = GameUtils.dictNames( context, m_lock );
DictUtils.DictPairs pairs = DictUtils.openDicts( context, dictNames );
Assert.assertFalse( pairs.anyMissing( dictNames ) ); // PENDING
boolean success = !pairs.anyMissing( dictNames );
if ( success ) {
byte[] stream = GameUtils.savedGame( context, m_lock );
Assert.assertNotNull( stream );
m_gi = new CurGameInfo( context );
@ -225,9 +226,10 @@ public class JNIThread extends Thread {
pairs.m_paths, m_gi.langName(), utils,
jniUtils, null, cp, m_xport );
}
Assert.assertNotNull( m_jniGamePtr );
m_lastSavedState = Arrays.hashCode( stream );
return this;
}
return success;
}
public GamePtr getGamePtr() { return m_jniGamePtr; }
@ -682,6 +684,7 @@ public class JNIThread extends Thread {
}
} // for
if ( null != m_jniGamePtr ) {
if ( m_saveOnStop ) {
XwJNI.comms_stop( m_jniGamePtr );
save_jni();
@ -690,6 +693,7 @@ public class JNIThread extends Thread {
}
m_jniGamePtr.release();
m_jniGamePtr = null;
}
} // run
public void handleBkgrnd( JNICmd cmd, Object... args )
@ -732,7 +736,7 @@ public class JNIThread extends Thread {
private void retain_sync()
{
++m_refCount;
DbgUtils.logi( TAG, "retain_sync(rowid=%d): m_refCount: %d",
DbgUtils.logi( TAG, "retain_sync(rowid=%d): m_refCount raised to %d",
m_rowid, m_refCount );
}
@ -755,7 +759,7 @@ public class JNIThread extends Thread {
stop = true;
}
}
DbgUtils.logi( TAG, "release(rowid=%d): m_refCount: %d",
DbgUtils.logi( TAG, "release(rowid=%d): m_refCount dropped to %d",
m_rowid, m_refCount );
if ( stop ) {

View file

@ -24,7 +24,6 @@ import android.os.Bundle;
import org.eehouse.android.xw4.XWActivity;
public class LocActivity extends XWActivity {
private static final String TAG = LocActivity.class.getSimpleName();
private LocDelegate m_dlgt;

View file

@ -25,7 +25,6 @@ import android.os.Bundle;
import org.eehouse.android.xw4.XWActivity;
public class LocItemEditActivity extends XWActivity {
private static final String TAG = LocItemEditActivity.class.getSimpleName();
private LocItemEditDelegate m_dlgt;

View file

@ -44,7 +44,6 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class LocItemEditDelegate extends DelegateBase implements TextWatcher {
private static final String TAG = LocItemEditDelegate.class.getSimpleName();
private static final String KEY = "KEY";
private Activity m_activity;

View file

@ -29,7 +29,6 @@ import android.widget.TextView;
import org.eehouse.android.xw4.R;
public class LocListItem extends LinearLayout {
private static final String TAG = LocListItem.class.getSimpleName();
protected static final int LOCAL_COLOR = Color.argb( 0xFF, 0x7f, 0x00, 0x00 );

View file

@ -26,7 +26,6 @@ import android.view.ViewGroup;
import android.widget.SpinnerAdapter;
public class XlatingSpinnerAdapter implements SpinnerAdapter {
private static final String TAG = XlatingSpinnerAdapter.class.getSimpleName();
private SpinnerAdapter m_adapter;
private Context m_context;

View file

@ -8,13 +8,15 @@ g_verbose = 0
def usage(msg=''):
print
if not '' == msg: print 'Error:', msg
print "usage:", sys.argv[0]
if msg: print 'Error:', msg
print "usage:", sys.argv[0], '[-c <??>]* [-l] [-h]'
print " Compares all files res/values-??/strings.xml with res/values/strings.xml"
print " and makes sure they're legal: same format strings, etc."
print " -c options, if present, limit the check to what's specified"
print " -l option lists available codes and exits"
print " -h option prints this message"
sys.exit(1)
def associate( formats, name, fmt ):
if name in formats:
forName = formats[name]
@ -43,13 +45,38 @@ def checkFormats( formats ):
else:
print 'WARNING: sets different for', name, curSet, testSet
# Make sure that if there's a positional param of one type (%s or %d,
# typically) in one set that the same positional in the other is of
# the same type.
g_specPat = re.compile('%(\d)\$[ds]')
def asDict(set):
result = {}
for elem in set:
match = re.match( g_specPat, elem )
if match:
index = int(match.group(1))
result[index] = elem
return result
def setIndicesAgree(set1, set2):
result = True
dict1 = asDict(set1)
dict2 = asDict(set2)
for index in dict1:
if index in dict2 and not dict1[index] == dict2[index]:
result = False
break
return result
def checkLangFormats( engData, langData, lang ):
for key in langData:
if not key in engData:
print 'WARNING: key', key, 'in', lang, 'but not in English'
elif not engData[key] == langData[key]:
print 'ERROR: set mismatch', key, 'from', lang, engData[key], 'vs', langData[key]
elif not setIndicesAgree(engData[key], langData[key] ):
print 'ERROR: illegal set mismatch', key, 'from', lang, engData[key], 'vs', langData[key]
sys.exit(1)
elif not engData[key] == langData[key]:
print 'WARNING: set mismatch', key, 'from', lang, engData[key], 'vs', langData[key]
def getForElem( data, pat, elem, name ):
splits = re.split( pat, elem.text )
@ -69,18 +96,49 @@ def getFormats( doc, pat, lang ):
for elem in elem.findall('item'):
quantity = elem.get('quantity')
if not elem.text or 0 == len(elem.text):
print 'plurals', name, 'has empty quantity', quantity, \
print 'ERROR: plurals', name, 'has empty quantity', quantity, \
'in file', lang
sys.exit(1)
else:
getForElem( result, pat, elem, name + '/' + quantity )
add = name + '/' + quantity
getForElem( result, pat, elem, add )
return result
g_dirpat = re.compile( '.*values-(..)$' )
def getCodes(wd):
result = []
path = wd + '/../XWords4/res_src'
for subdir, dirs, files in os.walk(path):
for file in [file for file in files if file == "strings.xml"]:
match = re.match(g_dirpat, subdir)
if match:
result.append( match.group(1) )
return result
def main():
if 1 < len(sys.argv): usage()
parser = etree.XMLParser(remove_blank_text=True, encoding="utf-8")
wd = os.path.dirname(sys.argv[0])
langCodes = []
allCodes = getCodes(wd)
pairs, rest = getopt.getopt(sys.argv[1:], "c:hl")
for option, value in pairs:
if option == '-c':
if value in allCodes:
langCodes.append(value)
else:
usage( "unexpected code: " + value + " not one of "
+ ', '.join(allCodes) )
elif option == '-h': usage()
elif option == '-l':
print 'Available codes:', ', '.join(allCodes)
sys.exit(0)
else:
usage()
# use the entire set if not specified
if not langCodes: langCodes = allCodes
parser = etree.XMLParser(remove_blank_text=True, encoding="utf-8")
# Load English
path = wd + '/../XWords4/res/values/strings.xml'
@ -89,14 +147,11 @@ def main():
engFormats = getFormats( doc, pat, 'en' )
checkFormats( engFormats )
path = wd + '/../XWords4/res_src'
for subdir, dirs, files in os.walk(path):
for file in [file for file in files if file == "strings.xml" \
and not subdir.endswith('/values')]:
doc = etree.parse( subdir + '/' + file, parser )
forLang = getFormats( doc, pat, subdir )
checkLangFormats( engFormats, forLang, subdir )
sys.exit(0)
for code in langCodes:
file = wd + '/../XWords4/res_src/values-%s/strings.xml' % code
doc = etree.parse( file, parser )
forLang = getFormats( doc, pat, code )
checkLangFormats( engFormats, forLang, code )
##############################################################################
if __name__ == '__main__':

View file

@ -2759,13 +2759,15 @@ countAddrRecs( const CommsCtxt* comms )
XP_Bool
addr_iter( const CommsAddrRec* addr, CommsConnType* typp, XP_U32* state )
{
return types_iter( addr->_conTypes, typp, state );
XP_Bool result = types_iter( addr->_conTypes, typp, state );
return result;
}
XP_Bool
types_iter( XP_U32 conTypes, CommsConnType* typp, XP_U32* state )
{
CommsConnType typ = *state;
XP_ASSERT( typ < COMMS_CONN_NTYPES );
while ( ++typ < COMMS_CONN_NTYPES ) {
*state = typ;
XP_U16 mask = 1 << (typ - 1);
@ -2834,16 +2836,14 @@ addr_rmType( CommsAddrRec* addr, CommsConnType type )
addr->_conTypes &= ~(1 << (type - 1));
}
/* Set of NONE is ok, but for anything else it's illegal to be adding a second
bit. Use addr_addType() for that. */
/* Overwrites anything that might already be there. Use addr_addType() to add
to the set */
void
addr_setType( CommsAddrRec* addr, CommsConnType type )
{
XP_LOGF( "%s(%p, %s)", __func__, addr, ConnType2Str(type) );
XP_U16 flags = 0;
if ( COMMS_CONN_NONE != type ) {
XP_ASSERT( COMMS_CONN_NONE == addr_getType( addr ) ||
type == addr_getType( addr ) );
flags = 1 << (type - 1);
}
addr->_conTypes = flags;

View file

@ -1,5 +1,6 @@
/core.*
obj_linux_memdbg
obj_linux_memdbg_curses
*.xwg
obj_linux_rel
log_*_*.txt

View file

@ -246,6 +246,9 @@ ifneq (,$(findstring DPLATFORM_GTK,$(DEFINES)))
POINTER_SUPPORT = -DPOINTER_SUPPORT
endif
CFLAGS += `pkg-config --cflags glib-2.0`
LIBS += `pkg-config --libs glib-2.0`
CFLAGS += $(POINTER_SUPPORT)
ifneq (,$(findstring DPLATFORM_NCURSES,$(DEFINES)))

View file

@ -170,6 +170,7 @@ writeToDB( XWStreamCtxt* stream, void* closure )
(*cGlobals->onSave)( cGlobals->onSaveClosure, selRow, newGame );
}
#ifdef PLATFORM_GTK
static void
addSnapshot( CommonGlobals* cGlobals )
{
@ -191,6 +192,9 @@ addSnapshot( CommonGlobals* cGlobals )
LOG_RETURN_VOID();
}
#else
# define addSnapshot( cGlobals )
#endif
void
summarize( CommonGlobals* cGlobals )
@ -330,6 +334,7 @@ getGameInfo( sqlite3* pDb, sqlite3_int64 rowid, GameInfo* gib )
gib->lastMoveTime = sqlite3_column_int( ppStmt, 10 );
snprintf( gib->name, sizeof(gib->name), "Game %lld", rowid );
#ifdef PLATFORM_GTK
/* Load the snapshot */
GdkPixbuf* snap = NULL;
const XP_U8* ptr = sqlite3_column_blob( ppStmt, 11 );
@ -342,6 +347,7 @@ getGameInfo( sqlite3* pDb, sqlite3_int64 rowid, GameInfo* gib )
g_object_unref( istr );
}
gib->snap = snap;
#endif
}
sqlite3_finalize( ppStmt );

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