Adding a second permission a while back resulted in two Actions being
received and acted on. Needed instead to group the two and receive a
single Action IFF both were granted.
Put up an error message if too many tiles selected for trade
(a condition that couldn't exist when the pool was guaranteed to
have at least 7 in it.) (It's a hack: there's not even an enum
giving Spanish's code, and the lang_locale stuff in info.txt isn't
making it into the .xwd format.)
I've learned a bit about java since writing that class. Should be faster
now without the sleep/polling. Also making it illegal to use blocking
lock() call on UI thread. There may be some assertions to fix in the
next few days.
Was seeing race condition on slowest device where JNIThread init hadn't
finished before the event loop tried to use the gamePtr. So use
wait()/notifyAll() to fix.
And: Don't start the foreground service with its user-visible
notification, as that's too obtrusive and the ACL_CONNECTED stuff seems
to work well enough. Launching timers on a new install is mostly for my
own dev use, but won't hurt user experience either.
On O and beyond it's possible to tweak notification channels separately,
meaning users can hide the new BT-is-running notification and still get
game event notifications. So add a button that takes you to the right
Settings app page.
Separate processing of sockets from accepting them so that when an ACL
CONN notification is received and we open a socket (but don't yet have a
Service running because the ACL thing is most likely for some other app)
we can set it aside to be processed once we do have a service. Use the
same block-until-non-null thing as in RelayService to keep that thread
free of NPEs.
Rather than just dropping it and going back to a wait that will likely
last forever. I *think* wait() throwing that exception means the
thread's being killed, in which case the exception should be thrown up
to the containing loop that will then exit.
I thought I had to stop using a service instance before returning from
its onDestroy(), but that made the UI incredibly laggy AND appears not
to be necessary. At least in a bit of testing things still work.
Oreo's creating a new service instance for every single intent passed to
enqueueWork, meaning a brand new set of threads with a new queue, empty
set of messages to be retried, etc. was created every time, and all
attempts to optimize and retry were broken. So: make the threads a
static singleton that are given a Service instance from onCreate() and
told to drop it from onDestroy(). The threads proceed until they need an
instance, then block until one's available. Seems to work on Oreo and an
older Android as well.