Use an array of actual objects rather than indices, and add an equals()
method, so checkbox status can survive changes in the set of available
items and even be reproduced when the objects backing them change (as
happens after a new BT scan finishes.)
Control whether wifi direct is enabled from build.xml, a file that's
already different for the two variants. The point here is to do a
release with permissions changes but without having to fix everything
wrong with wifi direct.
If user hasn't granted READ_CONTACTS permission, use the pairing of
numbers/names that's come from Contacts via the SMS invitation dialog.
Sometimes it'll have names for numbers that arrived via invitations. Do
some cleanup while at it to prevent stored BT mac addresses from being
looked up as phone numbers.
On launching SMS invite dialog, ask for READ_CONTACTS permission. Where
it's needed, though, is for the user-invisible process of translating
phone numbers to names (not launching the Contacts app via an
Intent). This just seems like the best place to ask since the user's
thinking about contacts and phone numbers.
InviteDelegate superclass now tracks whether something is checked,
though it's not doing as well as subclasses did before, e.g. when SMS
would uncheck everything but a newly added contact.
Add post-open test for SMS and then ask for SMS permission, giving
rationale if the OS says I should. Meant adding a new interface for
rationales and wiring that in. It's a bit spaghetti and I may think of a
cleaner way later.
When opening a game that sends via SMS, check if it has permission and
offer to remove the config if it doesn't, removing a similar check from
pre-opening code. (Here it'll catch e.g. games opened from the
GameConfig process.) Sends/receives without SMS permission are already
caught by existing catch{} blocks, so there's no crash.
Moving stuff into superclass and trying in general to simplify
things. BT and SMS invitation work, but the option to have more than one
player per device isn't available. RelayID invitation is a mess, but was
before I think. WiDir invitation crashes in assert because I can't
debug it on this branch. Lots of work and cleanup still required.
rewrite perms23 class to use Builder pattern, making it easier to pass
more than one required permission. Use that (with hard-coded set for
now) to check and ask for permissions a game needs to communicate. Offer
to remove the comms methods the user doesn't want to permit (but that's
not implemented yet.)
First, needed to remove some state caching since though a non-SMS
phone will never become one my ability to ask changes over time. Then
changed population of communication options to first ask for the
permission needed in order to find out what's supported, then to find
out what's supported via methods that will return false without
permission. Can't think of a better way right now....
Add a compile-time option to send commands in json as strings rather
than ordinals (ints) for easier reading of logs. And log/keep track of
when discovery's turned off or on in case it's useful for making all
this work.
In handling resend for a newly available transport, if the lock can't be
obtained see if that's because the game's currently open and if so post
to its thread.
Each time we get a socket to a peer, try sending all pending wifi direct
messages. It's a hack, but trying to send isn't that expensive and the
experience is much improved.
When contacting opponents, iterate over opponent addresses rather than
information cached in the summary. Start implementing for BT, but that
needs more work. Change enum names in WiDirService state machine. P2p
opponent notification untested because apparently an open hotspot, which
you can't prevent devices from connecting to, breaks P2P connectivity.
Rewrite to use new XWPacket class that wraps JSONObject but could later
support a binary format, and reply with new message when packet arrives
for a game that does not exist. Code already present turns that into an
invitation to delete the game.
fix race condition in accept thread; only call wifimgr.connect() on
guest side. Connectivity now works reliably if the guest starts, or is
restarted, when the group owner is running. If owner is restarted the
guest seems never to connect (without restart.)
Two crashes reported on the Google Play store in the 112 version have at
least easy work-arounds: catching exceptions and doing nothing. In both
cases that should be harmless, so assuming the causes are rare it's a
good move.
Make it a trivial state machine that implements Runnable and
ActionListener so it can be scheduled and notified easily. Removes a
bunch of code. Connecting still happens unreliably, but it should be
easier to tweak things now.
Add UI, minor thanks to recent refactoring, to allow invitations via
wifi direct. Uses a mapping of all currently known device mac addresses
to names, with only the latter shown to users. Works well, though
something I changed seems to have causes devices to start losing track
of their connections to each other.
Simple fix to the problem that a group owner may not be in the role of
game host: if I'm a guest and don't have a socket for the mac address to
which I need to send, slap src and dest addresses into the message and
send it to the group owner. That device can then forward it.
Found a recipe for service discovery that at least in the bit of testing
I've done is much more reliable. Devices connect almost
immediately. Basically everything chains through onSuccess() handlers.
URL to recipe is in code.
Examples kill it before calling connect(), so do the same. Seems to make
connection more reliable. (Pending: handle case where more than one
two devices are in the group!!!)
Made WifiDirectService into an actual service in order to better process
incoming packets. Now works for game messages from comms, and posts
notifications when app's in background. The latter requires using the
app context from XWApp since unlike the other transports this one
doesn't involve the OS invoking us with a Context.
Got to the point where I have an open socket for the packet I want to
send! Lots of changes to how discovery works seem to have improved
reliability though I'm still unimpressed. Much to learn.
Grab and store the local device's mac address. Add p2p as a type of
address, represented by the mac address of the recipient. Include the
local device's address in invitations sent when specified by user. Now
the WifiDirectService class is being passed a packet and the address of
the recipient; it will next need to set up sockets with every device it
encounters and map them to their mac addresses so that it can do a send.
Starting with the release of Nougat there have been cases where the
board would not correctly redraw. It's been most evident when using the
hit feature many times in a row, with something going wrong every fifth
time or so (but not that consistently.) It's as if modifications of the
bitmap backing BoardCanvas were being done asynchronously and not
necessarily all completed when I blit the canvas to the screen via
canvas.drawBitmap(). (As evidence of this I confirmed that a tap on a
tile in the tray after a bad draw would cause the screen to correct
itself even though the only additional rendering was to the tray. So by
the time that second drawBitmap() call happened the bitmap data was
correct: all draws that hadn't completed earlier had done so by now.)
The fix is to call Bitmap.createBitmap(bitmap) and to use the copy as
the source of the canvas.drawBitmap() blit operation. I suspect that
createBitmap() waits for any pending draws into its source to complete
before making the copy. Regardless, if this hasn't fixed the problem
it's made it so rare that I'm not seeing it, and since I'm only doing
the copy on Nougat there's little risk in the change. And I can't detect
any problems coming from the considerable additional memory being used
and immediately marked available for gc.
Starting with the release of Nougat there have been cases where the
board would not correctly redraw. It's been most evident when using the
hit feature many times in a row, with something going wrong every fifth
time or so (but not that consistently.) It's as if modifications of the
bitmap backing BoardCanvas were being done asynchronously and not
necessarily all completed when I blit the canvas to the screen via
canvas.drawBitmap(). (As evidence of this I confirmed that a tap on a
tile in the tray after a bad draw would cause the screen to correct
itself even though the only additional rendering was to the tray. So by
the time that second drawBitmap() call happened the bitmap data was
correct: all draws that hadn't completed earlier had done so by now.)
The fix is to call Bitmap.createBitmap(bitmap) and to use the copy as
the source of the canvas.drawBitmap() blit operation. I suspect that
createBitmap() waits for any pending draws into its source to complete
before making the copy. Regardless, if this hasn't fixed the problem
it's made it so rare that I'm not seeing it, and since I'm only doing
the copy on Nougat there's little risk in the change. And I can't detect
any problems coming from the considerable additional memory being used
and immediately marked available for gc.
commented-out logging of drawCell, with flags; debug-build checks that
static rects passed to java draw code aren't being used by multiple
threads at once.
Current code is hitting the relay every 60 seconds, at least on
non-google-play installs like f-droid. Switch to using a backoff timer
that maxes out at once per hour. Eventually may want to not run the
timer at all when there aren't any unfinished relay games present.
Now sends and receives a single packet more often than not. Disabled for
non-DEBUG devices, and new permissions that are required are commented
out so I don't accidentally ship before the sdk-23 permissions stuff
makes additions less scary.
Disabled at compile time, and missing permissions required, but if
enabled is able to discover other devices running same app. Next: try to
open a socket.
Meant using NotificationCompat, dropping FloatMath, and changing a bunch
of build config stuff. Not done for gradle builds yet. Currently crashes
on a new install until you go into Apps/Crosswords/Permissions and turn
on the four "dangerous" ones it's using. Now the work is to check for
and request missing permissions on demand.
Crash occurs when creating new game: because there's no turn set yet the
jboolean has no set value (whatever was on the stack). Apparently the
java runtime accepts only 1 and 0 for jbooleans.
Crash occurs when creating new game: because there's no turn set yet the
jboolean has no set value (whatever was on the stack). Apparently the
java runtime accepts only 1 and 0 for jbooleans.
This completes moving to using traditional logging. At least to having
each file provide a TAG. Class rather than TAG is passed in, and format
strings are preferred to contatenation, but now adb can work with the
output.
I think this was related to changing the order in which save operations
happen and that it's no longer valid to insist that there already be a
rowid at this point, but could be wrong....
Fixes problem with list view always being a move behind, since it's
saving not summarizing that was triggering the refresh, but summarizing
that added the data from which refresh/list view drew.
Idea is to have the games list stay in sync, but in fact it stays one
move behind, at least in a typical standalone human-vs-robot game. So
this is incomplete.
There are some screen dimensions, especially with dual-pane mode, where
the board is just bit narrower than the screen. Rather than have narrow
white borders, allow the cells to take up the slack. The API takes an
upper bound on the ratio of width to height so things shouldn't get too
odd looking.
Running into a case where views haven't been added to the layout yet but
I'm searching there for their associated fragments. Fix to NPE stops a
crash, but intents still aren't being handled. I need to try to handle
them later, but am unsure when to start trying.
Mistaken option to gtk_box_pack_start() meant the scrollbar got
allocated space along with the board when the container expands, not
what you want with a scrollbar.
Too-clever double loop had an no-exit path. Now it's simpler: find a
fragment that can handle the intent, pop all fragments to its right
until it becomes top-most (there may be none), and then give it the
intent. Use of popBackStackImmediate() is required so old fragments are
gone before intent handling wants to create new ones.
Since display is now by whose turn it is and how recently there's been a
move in the game, the order can change on every save. So in the listener
for saves, redraw the group the saved game belongs to. The best way to
do this without flicker seems to be to mimic closing then re-expanding
the group, so that's what I'm doing.
Getting an NPE iterating over fragment/children of dualpane view
because, I think, committing them's been postponed. So add the iteration
as a Runnable to the same postponement mechanism. This may be wrong:
needs to be run for a while to see if it fixes the NPEs I'm seeing (on
opening an intent in the morning after the device has been idle all
night.)
Attempt to fix crashes happening when the occasional fragment
transaction happens before the OS is ready. Keep a boolean indicating
whether we're in that state, and when it's not set create a Runnable to
be run next time it is. Temporary Toast lets me know when it's working.
Attempt to fix crashes happening when the occasional fragment
transaction happens before the OS is ready. Keep a boolean indicating
whether we're in that state, and when it's not set create a Runnable to
be run next time it is. Temporary Toast lets me know when it's working.
Problem: brain-dead Android code (on 5.1.0 anyway) caches the
SectionIndexer separately from the ListAdapter that implements it, so
when you change the ListAdapter it keeps using the old one for its
SectionIndexer. Solution is to replace the ListView in the layout with a
FrameLayout into which a ListView is inserted at runtime on init and
whenever the data changes.
Setting up an emulator that'll grab {menu,layout}-small resources is a
pain so this script exchanges them with regular resources so that a
subsequent compile will produce something that (when run) will catch
missing resources etc.
tweaks to BoardContainer and Toolbar to better position toolbar and
better hide/show it in tile exchange mode. The bar's still partially
offscreen sometimes on a 2.3.7 emulator but it's usable. Next I need to
try specifying the size of the bar rather than having it derive from the
size of the images it contains.
They crash on 2.3.7 at least, and don't seem to be required anyway. I
think the only reason I need to implement onMeasure() is because
BoardView expects to be called a certain way.
Correct or not, this is my solution to the circular problem of how to
choose a vertical or horizontal toolbar before beginning the layout of
the board and toolbar. Adding a new custom container that holds the
board, toolbar(s) and tile exchange buttons and uses the ratio of its
own dimensions to choose which toolbar to show. Also drive toolbar
initialization from the layout process because when started from
BoardDelegate it now tries to install button listeners too early.
Fix crash when game config opens dict download for result and nothing's
chosen. Was sending Activity.RESULT_OK in that case instead of
RESULT_CANCELED.
Docs and some logcat crash statements from the OS say I need no-args
constructors for fragments. So rework initialization and use bundling so
parent name doesn't have to be passed into the constructor. Seems to
work, and fixes the crash I was seeing (happened when sending an
invitation via SMS) but requires more testing.