Tag Archives: develop

WordMix 2.0

WordMix in Google Play Store

WordMix 2.0 is out! This is a due major update to my little word game for Android and includes a major face lift by bringing the game into the world of Material Design. To keep this simple, I dropped support for Android lower than 5, with a version supporting Android 4 still being available via Google Play Store. However to get the newest features you need to upgrade your device to Android 5.

Of course this update includes a number of bug fixes and general improvements, but here the major changes:

Material Design

Isn’t it pretty? The first thing you may notice is the immersive full screen mode, now spanning the status bar and extending over the navigation buttons, if present.

The action bar has been replaced with on screen controls to give more space to the background pictures and the board. So has the time progress bar given way to a simple timer. A dark button theme is easy on the eye and yet leaves focus on the game itself.

The game contains more background images and some of the old images have been replaced with new ones. All backgrounds are included in the free version, there are no more “premium” backgrounds.

This is just the first step, other screens will follow.

Bottom sheet for contextual information

Tapping a word will now reveal a contextual bottom sheet with information about the word. This for example shows the number of points for this word, whether the word is valid and has been played before and it may include actions of other apps.

If for exampe Google Translate or Wikipedia apps are installed, they appear as actions that allow the player to quickly look up or translate a played word.

Under the hood this will simply show any app that implements ACTION_PROCESS_TEXT, the same way this is integrated into Chrome.

The word suggestion feature now shows a list of possible words, their points, and allows the user to choose, with of course the option to first translate or look up the word to play. It allows to immediately set the word from the bottom sheet, which is very convenient.

New languages

Two new languages and dictionaries are now supported. Any feedback or suggestions for new languages is always welcome!

  • Czech
  • Polish

Available in Google Play and Amazon App Store

WordMix Pro in Google Play Store
WordMix in Google Play Store

WordMix is (c) Sascha Hlusiak 2012-2019.

iOS VPN ondemand probes and caching

In our company we push out a VPN configuration to iOS devices that contains on demand rules to only connect to the VPN when not in the company network, based on various criteria.

TL;DR: unexpected caching behaviour of NEOnDemandRuleDisconnect.probeURL

We discovered that iOS (12.3.1) appears to aggressively cache the response of the probeURL when using NEOnDemandRuleDisconnect on demand rules in a VPN configuration.

The response is cached in certain situations, causing the rule to match when it shouldn’t and not to match when it should. This cache was only reset on rebooting the device and not when switching networks. We did not even see new DNS requests for the probeURL when switching between networks, which was even more problematic as we use Split-DNS for the resource that was probed.

The VPN on demand rules were evaluated every time the network changed, but the probe wasn’t sent and the rules still matched on the cached response.

  • When returning a 200 OK, make sure to add Cache-Control headers!!
  • Do not return 301 Moved Permanently!!

Checking for a HTTP resource

The “probe” resource was only available from within the company network, controlled by Split-DNS.

  // disconnect if "probe" returns 200 OK
  let rule1 = NEOnDemandRuleDisconnect()
  rule1.interfaceTypeMatch = .wiFi
  rule1.probeURL = URL(string: "http://company.com/probe")
  rules.append(rule1)

  // otherwise connect
  let rule2 = NEOnDemandRuleConnect()
  rule2.interfaceTypeMatch = .wiFi
  rules.append(rule2)

The probe returned a 200 OK when queried within the company network. Publicly the DNS entry was pointing to a S3 bucket which did not contain the probed resource.

NEOnDemandRuleConnect and probeURL

We use the NEOnDemandRuleConnect classes that are attached to a VPN configuration. The documentation of the probeURL attribute is fairly sparse:

var probeURL: URL?

An HTTP or HTTPS URL. If a request sent to this URL results in a HTTP 200 OK response and all of the other conditions in the rule match, then then rule matches. If this property is nil (the default), then an HTTP request does not factor into the rule match.

https://developer.apple.com/documentation/networkextension/neondemandrule/1405981-probeurl

Apple’s Configuration Profile reference adds:

A URL to probe. If this URL is successfully fetched (returning a 200 HTTP status code) without redirection, this rule matches.

Cache rules

With extensive testing and sniffing we discovered the following cache behaviour of iOS for probeURL:

  • 301 Moved Permanently is cached for ever
  • 200 OK is cached for ever, if it contains content, ETag and Last-Modified headers and no Cache-Control.

Once a response like this has been seen, iOS will not send another DNS or HTTP query and will use the result until the device is rebooted.

In the case of the 301, the rule will always not match (as iOS will not follow redirects). In the case of the 200 response, the rue will always match, no matter what network the device is currently on.

Unexpected caching behaviour

Obviously the result of an on-demand probe should never be cached beyond the network boundaries, as it defeats the probe pointless.

Further we were expected to see at least DNS requests for the resource when switching networks as we use Split-DNS. Assuming that a response is still valid when DNS returns a different IP address is surprising.

When a resource returns ETag and Last-Modified headers and no further Cache-Control headers, we expected clients to validate whether the resource has been changed (304 Not Modified) rather than it being cached without validation.

Cache-Control headers

Adding the following header to our 200 OK response, caused iOS to always request the resource when processing the on demand probes:

Cache-Control: no-cache, no-store, must-revalidate, max-age=0

Selector.select() returns 0 immediately without blocking

TL;DR

If using non-blocking IO and setting SelectionKey.interestOps(0), a Selector will wake up on POLLHUP | POLLERR (e.g. connection reset by peer), but the JDK /Android SDK will not be able to surface this condition to the caller and will return 0 instead, potentially causing a loop with 100% CPU utilisation.

Details

I was recently investigating an issue with an Android Selector going into a busy loop where select() would return immediately without any keys being selected.

From the Android API documentation:

This method performs a blocking selection operation. It returns only after at least one channel is selected, this selector’s wakeup method is invoked, or the current thread is interrupted, whichever comes first.

I knew that neither the current thread was interrupted nor that the selector was woken up, yet the select() returned with an empty selected key set, consuming 100% CPU in the resulting busy loop.

There are a few reports of similar problems, e.g.

In particular that first link suggests that other implementations have encountered this when using the JDK and found workarounds like recreating the entire selector based on a heuristig.

After trying many things and digging through all related Android/Java/JNI classes I have finally found the cause of the spurious wake ups, which appears to be a bug in the JDK or an illegal, yet undocumented, use case when using
selectionKey.interestOps(0);

Program flow pseudo code

Our selector loop detects when channels are ready for reading but would aim to offload the actual reading of the data to a secondary thread.

do {
  // block until any channel is ready
  int ret = selector.select()
  // for any key that is ready
  for (key: selector.selectedKeys()) {
    if (key.isReadable()) {
      // make sure we are not waking up
      // until reading has finished
      key.interestOps(0);

      // offload the reading to a worker
      // the worker will call
      // key.interestOps(OP_READ) when done
      workQueue.add(key.channel());
    }
  }

  // make sure all selected keys are cleared
  // because we've handled them all
  selector.selectedKeys().clear();
} while (true);

As illustrated, once a key has been detected to be ready, we unregister all interested in all operations and offload the read work to a secondary thread. We did this by calling key.interestOps(0), and pass the channel to a worker thread. When the worker thread has completed the read, it registers the channel again with key.interestOps(OP_READ).

We observed a situation where select() would constantly return 0, with the selectedKeys set being empty, causing 100% CPU load.

Missing support for interestOps(0) in the JDK

The JDK / Android SDK promises that select will only wake up if any key is ready, the selector is woken up or interrupted, but neither of these things have happened. The documentation does not mention a special handling of interestOps(0) and it can be assumed that this is a valid operation to perform.

Under the hood Java and Android SDK are using poll(2) to block for the I/O ready state. The pollfd struct takes an events field (which in our case is 0) and it would populate a revents field with the values of the ready file description.

I found that poll(2) wakes up with revents being POLLHUP | POLLERR as a signal that the remove channel is closed. This is a valid case even when registered events is 0 and any read on such an fd would return -1.

The Android AbstractPollSelectorImpl.java however FILTERS the read the nioReadyOps() by the nioInterestOps():

sk.channel.translateAndSetReadyOps(rOps, sk);
if ((sk.nioReadyOps() & sk.nioInterestOps())!=0) {
  selectedKeys.add(sk);
  numKeysUpdated++;
}

So even if nioReadyOps() would return a value, it would be masked out by the nioInterestOps(). Unfortunately, the translateAndSetReadyOps() in SocketChannelImp.java will ensure that even nioReadyOps() is 0, because it is set to intOps in case of error:

if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
  newOps = intOps;
  sk.nioReadyOps(newOps);
  // No need to poll again in checkConnect,
  // the error will be detected there
  readyToConnect = true;
  return (newOps & ~oldOps) != 0;
}

Endless loop on interestOps(0) and POLLHUP | POLLERR

A selector will wake up if a registered channel has been disconnected even if interestOps has been set to 0!

However there is no way to access this condition in the userland because the condition has been masked out by the zero of interestOps. The selector will return an empty selectedKeys set instead even though poll signalled a ready file descriptor.

Fly as a chicken!

Chicken Tournament for Android received some updates recently, with some great improvements. Chicken can now fly!! This took a while to get right and I have replaced the very complex and realistic approach with much simplified mechanics (on the cost of loopings or barrel rolls).

Use either the on-screen D-Pad or fly using the device sensors.

Now I just need to teach the Computer chicken how to fly. 🙂

Check out the promo video below

As always only available in the Google Play Store:

Chicken Tournament Demo on Google Play

SEQTA Learn and Engage Android Apps

The SEQTA Android Apps for Learn and Engage are now available in the Google Play Store. While the iOS App has been developed in-house by an external developer, I developed the Android versions as a side project at home. The Apps were later handed over and integrated into the portfolio of the company.

SEQTA Learn and Engage are (c) SEQTA Software, 2017.

The two Apps are mostly identical other than branding and the target audience and feature native login experience, QR Code scanning for signing in via a code, push notifications and a webview to display the content. They support multiple accounts and support modern Android features like launcher shortcuts.

Android Apps free in Google Play

SEQTA Engage Android App
SEQTA Learn Android App

Read the official announcement or FAQ.

Screenshots

WordMix on tablets, learning Japanese

A recent WordMix update brings much improved support for Android tablets as well as experimental support for Japanese dictionary.

Improvements to the layout for 7″ and 10″ Android tablets were long overdue, fixing some issues where activities and controls looked out of place because they were initially created and optimised for mobile phones.

WordMix in Google Play Store

Further I based the App’s theme on Holo for Android 4 and on Material for Android 5, ditching the DeviceDefault as a recommendation. In my experience, vendors quite often ship a DeviceDefault implementation, that is inconsistent, incomplete and quite often breaks visual appearance. In order to work around inconsistent presentation on some Android devices, I have decided to pin the theme to a set of known appearance with some custom styling, bringing a consistent look across all Android 4 and Android 5 devices (Android 2 and 3 support has been removed).

WordMix Pro in Google Play Store

Only new feature is the experimental support for Japanese as a language, including a Japanese dictionary (needs to be downloaded after installing the App). Japanese is particularly difficult to implement in this game due to the high number of different letters and combinations. Similar sound combinations have been combined as single letters, allowing to choose the specific sound by tapping on the dice. Feedback is appreciated!

As always, get it in Google Play Store, while it’s hot!

Water splashes

Sometimes tiny little details can make all the difference. If an egg in Chicken Tournament for Android hits the water, a watery particle system is spawned for the splash. This is just a modification of already existing particle systems but it feels super nice and looks flashy. Of course this is miles away from looking like real water but that’s not the goal and the pure reaction and feedback of an egg hitting the water does make all the difference.

Chicken Tournament for Android

Long time no post about the Android version of Chicken Tournament. But it’s doing very well, despite lack of time. 🙂 And the best, you can already check it out in Google Play!

Screenshot_2014-09-07-16-14-52

New particle systems

A couple of updates later, the completely rewritten game now features improved particle systems like blood, feathers and fire and comes with limited keyboard support. Especially the new feathers took careful design and tuning to get the physics right but I’m very pleased with the optic result and performance. Of course, cranking up the amount of effects, I’m sure it can bring every device down.

UI sound effects improve overall feeling and experience. Having in mind that this game was completely written from scratch using a self written engine and pretty much not reusing any code, I am extremely proud of the result.

Career mode

Screenshot_2014-09-07-17-50-27

The new career mode features an experience and skill system for your hero, level by level. You can collect different hats that will further improve your skills and stats.

In Google Play

Chicken Tournament Demo in Google Play
Chicken Tournament Demo in Google Play

 

The demo version can be downloaded free of charge, it’s ad-free but has a limited feature set. Those features are without limitations tough, like pay-2-win or In-App-Purchases. There is a fully featured full version, meant to support me and my work.

But some important features are still missing though, like:

  • Multiplayer mode
  • Playing as chicken
  • Highscores and ranking lists
  • More and more and more optimisations

I’m just one man, please be patient. If you find bugs of have suggestions, please email me at ct@saschahlusiak.de.

Screenshot_2014-09-25-21-48-16

Thoughts on Google Play Game Services and games

I recently updated the Google Play Game Services library of Freebloks 3D for Android and the BaseGameUtils, as recommended by Google. Not reading the ChangeLog, I was confused that my game tried to auto log in to Google on the start, disrupting the user experience I built around that. Even after dismissing the login dialog once would show the dialog again in the next Activity that is derived from BaseGameActivity or uses a GameHelper object.

Searching the Interwebs I found the FAQ, which explained the change of behaviour, and I am sad that the game itself once again becomes more and more insignificant:

The default behavior of BaseGameActivity and GameHelper is to show the user the sign-in flow (consent dialogs, etc) as soon as your application starts. Naturally, once the user signs in for the first time, they won’t see the consent flow again, so it will be a seamless experience. […]

The first time a game is started, the user will be prompted with a full screen dialog asking the user for consent to post on their behalf to Google+.  The user hasn’t seen anything of my App yet and still Google tries to put itself into the foreground. After the user signed in, this might become a seamless experience but being prompted with this dialog does not seem like a good experience. Especially because there is no warning or explanation of what this dialog does.

It is important for the user to sign in as early as possible so your application can take advantage of the Google Play Games API right away (for example, saving the user’s progress using Cloud Save, unlocking achievements, etc).

I noticed that usually I want to explore the game a little before signing in to Google. I’d like to find out if the game is a game I’d continue to play and once I get engaged with a game, I am willing to sign in to use the additional features. I know I am not an everyday user and I am aware that logging in to Google gives up some privacy. And before I haven’t decided to continue playing a game, I do not want any information to leak or social activity to be generated.

Obviously this reads to me as:

it’s important for the developers and Google to get user generated activity and data as soon as possible.

And is again another step towards games telling the users what to do.

If the user cancels the sign-in flow, BaseGameAcitivity/GameHelper will remember that cancellation. If the total number of cancellations reaches a predefined maximum (by default, 3), the user will no longer be prompted to sign in on application startup. If that happens, they can still sign in by clicking your application’s Sign In button, if you provide one.

Is not signing in to Google not a choice anymore but an error? If I dismiss the dialog because I do not give consent, is that assumed to be an error? Do I have to be prompted again even though I made the choice to not log in? Do I really have to dismiss the dialog 3 times until the game believes me that I do not want to log in?

The games are taking over!

I noticed the trend of games beginning to control users, of being needy, wanting attention, and developers seeing games only as a way to generate a stream of content or resources back to the developer.

Games these days:

  • show popup notifications that they want to be played.
  • make the user attend the game by long running tasks in the background that finish whenever. Building a building may take 5 hours, after which I have to open the game again.
  • want you to share everything on Facebook or Google+ (“Your creature took a dump. Share on Facebook?”). This is not to make you happy or to provide a game element, it is purely to attract other people and make them install the game.
  • tell you exactly and in detail how to use it. A lot of games begin with a 10 minute intro (“now click here”, “now buy upgrade”, “now shoot”) to make sure that the user understands the concept of buying upgrades and in game currency. This leaves very little room for experimentation and explorations, because users need to follow the strict predefined path that generates revenue.
  • lock you in. Using In-App-Purchases basically makes you rent the game, it is like Prepaid and the decision to stop playing a game is harder, because you have money that will expire. When you buy a game and own it, you have the freedom of choice to not play it. Buying your right to play the game over and over will most likely leave you hanging in an awkward spot when you decide to stop. Oddly enough these games are advertise as Free or Free2Play or, less often, Pay2Win.
  • use gamification to seem more interesting. Most games implement achievements in a way, so that they are not game elements. The Google Play services offer achievements that are outside of the game, meaning they don’t change the game flow, giving the user no actual value of an earned achievement. While the wording suggests the user benefits from earning an achievement, this is likely to drive engagement with the game but will not result in higher user experience or even fun. I fear the day users wonder about the motivation to achieve anything.
  • artificially restrict themselves but still take over your time. Why does building a house takes 5 hours sometimes, while the game does not any other game elements during that time? I’s making me hooked, telling me to go on with my day but of course I will always have the game on my mind and I have to come back after 5 hours. The game dictates when the user can play with it and when he can’t. It is not the users decision anymore to play and spend time with the game.

Where did the games go that gave power and freedom to the players to do what they want to do? With room to explore? With having game elements to actually fill 5 hours of time, then waiting and being ready when I come back to it? Where did the love go to provide the user with a fun way to pass his time?

This is not about the user anymore. He is not the customer, he is the good to be sold, the “conversion” to be made. The game is just the means and additional game elements are in the way. Games became a pure medium for developers and Google to say to users: “Give me your money”.

Where was I? Oh yes, disable the auto-login.

Easy enough the above behaviour can be reverted by

getGameHelper().setMaxAutoSignInAttempts(0);

but that’s not the point. Give the power back to the user!

moosic.fm in google play

The client app for moosic.fm is available in Google Play. It is by far my most polished and stylish app, that I developed for the German start-up moosic.

moosic.fm in Google Play
moosic.fm in Google Play

With moosic.fm you can keep track of the music that’s running in your favourite location. Browse past playlists or see what’s playing right now, all together with previews and cover pictures.

In the backend, the moosic listener listens to music in the background and uploads the recognized songs as a playlist. Users can browse these playlists using either the nice web frontend or the native Android App.

Note that the technology is currently being tested and evaluated. Kodus to T O-12 in Stuttgart for being available for the beta test and to Gracenote for their music recognizing api. For questions, don’t hesitate to contact the guys at moosic.de.

Screenshots

Chicken Tournament for Android in development

After more than 10 years I decided to port Chicken Tournament to current Android smartphones. Due to the differences between the platforms, this will result in a new game and a new engine, but because of lack of time and resources, I will reuse the models and most of the textures. OpenGLES 2.0 though allows me to massively improve the quality of the graphics.

The PC version and the android version will not be compatible.

Please follow the official Chicken Tournament facebook page to receive more information and updates. A very early development version allows driving the harvester over a plain using the accelerometer to steer. The chicken are nicely animated using vertex shader.

Development screenshot of CT for Android
Development screenshot of CT on my S3

In-App Donations in Freebloks 3D

Freebloks 3D for Android is the Android port of the PC version of Freebloks 3D for Windows and Linux. Like the PC version, the Android port is completely free software, available for free in the Google Play Store and the source code being available on GitHub.

I strongly believe in Open Source software and that it can help to make the world a better place by making knowledge and power available to everyone. While many hours of work went into the Android port, I feel good to completely open the software for others to study, to modify or contribute. A lot of my knowledge and skills come from the study of others work and my contribution to open source software is my attempt to give something back in return.

If you like Freebloks, please be encouraged to contribute, send be feedback, work on the code or support the developers with a donation. The recent update makes in-app donations available for users. These in-app items acknowledge the work of the developers and are completely voluntary. Freebloks will always be free but relies on your contribution!

So if you think, the game has some value for you, please consider a donation of your choice.

Screenshot_2013-05-05-10-01-35

Much improved AI speed for Freebloks for Android using jni

For the port of Freebloks 3D to Android I rewrote all code from C to Java. While that was working fine and resulted in greatly simplified networking code, the speed of the AI was not so great. It took up to 10 seconds on a fairly powerful SGS 2 for the computer to find a good move.

I was trying to move the CPU intense routines of the AI to C again, using jni as a bridge between Java and C. The simple network routines should stay in Java.

But the transfer of relevant game data to C and back to Java turned out to be very ugly, yet the solution was incredibly simple:

The Freebloks code was always split in two parts, the GUI/client part and the AI/server part, with the client and server always communicating using network sockets. Yes, even the single player version starts a network server and connects to localhost. The original source code always contained a package for running a dedicated server.

It was incredibly easy to copy the dedicated server code into my project, compile the C code with the NDK and connect it to Java with only a single jni call. It was running out of the box, with almost no change of the original C code at all! Since the server is running in a thread started from the native C code, there is no additional jni call neccessary and no data transfers except for the sockets.

The average duration for the AI to calculate a complete game dropped from 87 sec to 28 sec on my SGS 2. The version 0.0.2 in the Google Play Store supports ARMv5, ARMv7 and x86. Grab it now! You may also download a free apk file here.

And please don’t forget to give feedback.

Screenshot_2013-02-11-14-27-24

Out of Memory in GLSurfaceView on resume

The Symptom

After publishing WordMix with the OpenGL accelerated 2D game view (using GLSurfaceView), I received weird crash reports from some devices, mostly out of memory from within the GL context:

android.opengl.GLException: out of memory
 at android.opengl.GLErrorWrapper.checkError(GLErrorWrapper.java:62)
 at android.opengl.GLErrorWrapper.glGenTextures(GLErrorWrapper.java:350)
 at [...]

From the very limited information the Google Play Developer Console gives me about crash reports, I assumed it only affects devices running Android version 3. Modifying the code only caused the out of memory exception to be thrown at random other places, even at GL10.glClear(…)!

I also found out, the crash only happens when the user finishes a subactivity that would leave to the activity containing the GLSurfaceView. Users were complaining about the crash happening before starting a second game, which puzzled me, because all my rendering code seemed to be working fine on all devices running Android 4. Everything worked fine without the GLSurfaceView as well.

Looking that the source code for GLSurfaceView, nothing interesting was changed between Android 3.2 to Android 4, so the GLSurfaceView was hardly to blame, but more the hardware, drivers or specific OpenGL implementation.

The problem

The actual problem was very hard to track down and took me several hours and was particularly hard because I did not have an Android 3 tablet for debugging:

Up to Android 2.3, views were drawn in software and later composited using the hardware. Android 3 introduced an alternative hardware accelerated drawing engine for everything that uses Canvas classes. This alternative render path is disabled by default in Android 3 and supposedly enabled by default in Android 4 (previous blog post).

When I found out, that the Samsung Galaxy S2 does not enable hardware acceleration by default, I did set

<application android:hardwareAccelerated="true" ...>

in the AndroidManifest.xml for all activities that should support hardware acceleration. Using hardware acceleration for the activity with the anyway hardware accelerated GLSurfaceView did not make much of a difference. But accelerating the results or preferences activity, for example, gave a nice performance boost on my SGS2.

It turns out that the crash happens in Android, when an activity, that contains a GLSurfaceView, is paused for a fullscreen activity, that is hardware accelerated. When that hardware accelerated activity is finished, the underlying GLSurfaceView is screwed up, throwing out of memory exceptions, even though the GL context is completely reinitialized correctly.

The solution

Yes, I should have tested more the effects of hardwareAccelerated=”true”.

Leaving that attribute entirely unset is recommended for Android 3, especially when you use a GLSurfaceView, and should not hurt Android 4 devices as well. Setting a reasonable default value is then up to the manufacturers.

Summary

  • If you use a GLSurfaceView in an activity
  • and suspend that activity by starting another fullscreen activity
  • and that activity is hardwareAccelerated by setting so in the AndroidManifest.xml
  • and you target Android 3 devices
  • expect weird behaviour like out-of-memory exceptions

Welcome to fragmentation. Just let hardwareAccelerated be unset.