So now all jni code uses a single dutil context, but also a single
mempool and jniutil instance instead of new instances of the latter two
per game and dict-iteration.
A number of jni calls were "stateless", which meant they allocated their
own vtmgr and mpool instances each time invoked. Instead invoke them
with the global jni closure and add to it vtmgr (already has mpool) and
use these instead of allocating/freeing each time. To make sure no race
conditions are introduced (mpool, though debug-only, is probably not
thread-safe), guard these new uses with an in-use flag. If that fires
I'll need a mutex or something.
Somehow I got a wordlist into a location different from what was
recorded in the DB table and since the delete command matched on
location as well as name it was never deleted (which meant the checksum
was never updated and so upgrading never seemed to succeed.) Removing
the match on location fixed that problem, and since I don't see any harm
in cacheing only one version of a wordlist will simply leave it that
way.
Did a bunch of cleanup as well.
I'm seeing several IllegalStateException crashes due to e.g. having an
alert posted when app's in the background. Need to fix them, but the
debug build crashing isn't helpful. Log.e() instead.
The pesky thing is back. When app's in the background with an
unconnected game open displaying the "resend/wait" alert and the game
connects get IllegalStateException because the fragment stack's being
modified after onSaveInstanceState() (or, because the dialog fragment,
saved as an instance variable in BoardDelegate, dates from an earlier
state. Anyway, catching and dropping the exception and elsewhere failing
silently to rebuild the alert seems to fix the problem, but the right
fix is likely different. I suspect hanging onto that iVar is wrong, and
that the dialog should go away when onStop() is called and then be
rebuilt later from saved state. But for now, not crashing is good.
Remove a bunch of duplicated code, replacing with implementation in
XWService. Fixes duplicate invitation and game opening policies being
slightly different.
Try some funky layout shite to get, within a horizontal linear layout,
the first text field trucated if necessary so that the second (holding
the score) can be fully displayed. Tested on exactly one emulator so
far.
Try some funky layout shite to get, within a horizontal linear layout,
the first text field trucated if necessary so that the second (holding
the score) can be fully displayed. Tested on exactly one emulator so
far.
I think there's a bug in Weblate because I've seen this before: where
the English provides only an <other> the translation comes back with
only a <one>. That's wrong. Try adding a <one> in the English case to
see if that makes a difference.
I think there's a bug in Weblate because I've seen this before: where
the English provides only an <other> the translation comes back with
only a <one>. That's wrong. Try adding a <one> in the English case to
see if that makes a difference.
Otherwise it takes too long to scroll if you have hundreds of
games. To make this work had to move scroller to left side of games
list display as otherwise the scroller steals events from the expander
thingies.
Likely because of something in the jni world unset per-player dict name
is empty string rather than null, so test for that too. Fixes dicts
popup in newly-created game have an empty first line " (in use)".
I like this better than the previous fix: rather than share a
thread->env map with the game world allocate a new one for each
iterator. This could cause problem if the iterator is used on threads
that don't currently call map_thread(), or if there are callbacks that
need to look up the env that I'm not aware of. Needs testing...
Stumbled on a NPE opening up the wordlist browser configuring the first
game on a new install. So now test for null there and init early if
necessary. Seems to work, and won't do anything in places were not
needed.
Remake the min and max spinners every time either value changes so they
can't be used to set nonsensical values. (Which leads to immediate
crashes.) I'm sure this wasn't always a problem, but...
As reported to google, dict iterator destruction was crashing due to a
race condition if it happened after a game using the same dict had been
closed since it needed a mapped env that the game closure would
remove. Fixed in two ways, one by adding the mapping prior to the code
that uses it (a common pattern: add happens many times, whenver it might
be needed, but remove only once), and second by passing env into the
code that was crashing.
The mapping stuff remains inherently racy and I'm not sure now how to
fix that. It depends on there being a place to unmap after which it's
guaranteed the mapped value won't be needed again. When two
objects (game and dict_iter in this case) map the same env/thread combo
there's a race.
Looks like the assertion was left in when adding support for dual-pane
mode, as all other onPosButton() implementations called super rather
than assert. Which this one does now too.
Getting ANRs because (I think) the main thread's waiting for the write
thread to die and now the write thread's doing a ton of work
sometimes. So move the threads into a standalone object that can be
allowed to die on its own time without anybody waiting.
I *think* the reason I'm occasionally seeing toasts about not finding a
move is that when the engine's interrupted by there being a UI event in
the queue that error is posted. Instead try posting only when at the end
of the search nothing's been found.
Having reconfigured to use non-existent relay port as a test of falling
back to the web apis, tweak stuff: send the packets that have been
accumulated when an EOQ is found (rather than dropping all of them
immediately) before exiting the write thread; and start the threads up
when posting a packet in case they aren't (they may not be when the post
happens via timer firing.)
Seemed to be causing ANRs. Integrate instead into outgoing message queue
by using poll(timeout) then checking for unack'd packets every time
through the loop (but not more than once/3 seconds or so.)
Presence of timestamp instead of a boolean determines whether packet
should next via Web. Timestamps might also allow to process a larger
number of unacked packets in a single timer fire....
Track ack'd and unack'd packets. When there are ten more of the latter,
skip the UDP-send step. This is probably not the algorithm I'll settle
on (an explicit PING to the relay over UDP might be simpler), but it's
simple and easy.
Send each packet via UDP if that's thought to be working (always is,
now) and start a 10-second timer. If it hasn't been ack'd by then,
resend via Web API. Tested by configuring to use a UDP socket that the
relay isn't listening on. Only problem is that the backoff timers are
broken: never stops sending every few seconds.
The plan's to use the native relay protocol first, then to fall back to
the slower but more reliable (esp. on paranoid/block-everything wifi
networks) webAPI. This is the name change without behavior
change (except that the native kill() to report deleted games is gone.)
When grouping to allow multiple packets per outbound API call I forgot
that some are there to mark the end-of-queue: can't be sent! Trying
caused a NPE. Now if any EOQ is found in the queue that batch is dropped
and the thread's exited.
Making the right_side elem match its parent height prevents the
lower-right region of game list items from falling through and
triggering a toggle-selection event.
Making the right_side elem match its parent height prevents the
lower-right region of game list items from falling through and
triggering a toggle-selection event.
As expected, moves are no longer received instantly because the UDP
socket isn't available for the relay to write too once the URL
handler (relay.py) finishes.
Ideally the comms module wouldn't go through its connecting routine in
order to join a game. To that end I added a join() method to relay.py
and code to call it. Joins happen (pairing games, starting new ones,
etc.), but after that communication doesn't. First part of fixing that
would be to make cookieID persistent and transmit it back with the rest
of what join sends (since it's used by all the messages currently sent
in a connected state), but I suspect there's more to be done, and even
that requires a fair number of changes on the relay side. So all that's
wrapped in #ifdef RELAY_VIA_HTTP (and turned off.)
Was coming in as a string when called via curl. This may be a problem
for other ints if I go with lots of params instead of a json, which is
looking less likely.
join's how devices will create or join existing games. It more
compilicated than I'd like but seems to work except that once a slot's
assigned it's unavailable to anybody else even if the other fails ever
to respond (i.e. needs the ACK function of the c++ relay.)
ACK doesn't need to wait 2 seconds for a reply, and when it does so the
next send waits too. Eventually we'll want to combine messages already
in the queue into a single send. For now, this makes things better.
So far uses curl and json-c to send b64-encoded data to new script
which is able to echo the data. Next that script will need to open a
UDP socket to the relay and return results that appear before timeout.
Working around there being a border around the game-type image area.
With this change long-tapping works only on the right 2/3 of the
region. There might be a fix, but it's still better than there being
a hole (the border) in the thing where behavior's different.
Duh. The .java file was removed, but the declaration that all apps can
handle an intent (that requires WakeLock they no longer all have) was
not. Should fix crashes I'm seeing.
Board and Games List were using same menuid which meant that even when
chosen from Board's menu it would up getting handled by GamesList (in
dual-pane mode.)
Somehow the d variant was crashing without the WAKELOCK permission, the
OS having invokes something GCM-related. This should ensure nothing
GCM-related can ever happen.
This seems to fix that app, when built by me where GCM_SENDER_ID's set
in the environment, being a battery hog. Apparently google's code
doesn't handle being passed the wrong senderID very well.
I'd added inputType="text" everywhere I added maxLines="1" but it turns
out that breaks touches being handled at least on some devices. And it
makes no sense to have an inputType for something user can't put into.
Several EditText fields are configured so monkey breaks things, e.g. by
entering too much text in the default player name config. Fix. This
probably won't impact users but it lets the monkey tests move on to
other things that might.
Can't repro on Nexus emulator running 4.4 nor on Samsung running 4.4.4,
but the reporter says this fixes it. And from reading it appears
expecting older devices to load Material themes without an AppCompat
library is wrong.
For the ORDER BY clause that governs how games are displayed within a
group, use a static string built from a list of clauses that are then
easy to move up and down. Add clause that moves games with unread chat
to the top. Another commit will modify the display so it's clear why
it's there.
Bring back the test for being null, and add an additional one via a new
boolean iVar that we haven't tried posting it already. On some devices
there's enough of a lag that the is-null test passes several times
before the first makeDialog() call, leading to a cascade of attempts to
create that hangs the UI. The test's needed, but only once should be
start the process.
When the back stack is restored commit() is not called, so the fragment
needs to save it. Without this 0 is passed to popBackStack() and
everything's dismissed, not just the one fragment.
Rather than just pop whatever's on top of the back stack, which might be
the alert whose listener called finish(), use saved commit() ids to pop
down to the fragment itself. This feels like a risky change, and it's
tested only by back-button-dismissing the Wait alert in an unconnected
game in BoardDelegate, so needs some bake time.
When SDK >= 19 there's an API to tell if a listview is full enough to
require scrolling. So use that, rather than the raw count of games, to
decide whether to offer new users to hide the new game buttons.
What's here is merged with the main one, so no point in duplicating and
it's just a pain to maintain. Remove as much as possible that's not
unique to the debug variant (crashlytics and wifidirect, basically.)
Oops. Debug build assertion showed I was leaving an infrequently used
field out of serialization, adn then required that that object be
Serializable and implement equals() to pass more tests.
Get rid of treating 0 as a legit date (1970 being illegit). Tweak
formatting. It's not perfect, but few people see it so we'll see how it
goes during development.
revert a bit, dropping use of git revision and repo to provide an
order. Instead use aapt (which is an ubuntu package now) to pull the
version code and appID from .apk files, order by versionCode, and
secondarily by file mod time.
Auto-update was based on my manually setting what the newest is. Better
to use the git revision stored in the .apk, or failing that (later) in
the file name, to determine "age". This is all based on forcing a linear
order on git commits, but at least at the granularity of releases that
should be ok.
Mistake was putting "download more languages" at the bottom of list of
wordlists in one language. Having separate strings is a bigger change,
and in context just "Download more" works in both cases. Change name of
string so translators will notice.