How to fix: Android Connected, No Internet with Pi-Hole

Since quite a while I was running a Pi-Hole DNS server in my network to block ad- & tracking requests for all devices in the network (more info about Pi-hole are on Wikipedia).

All was great until at some time our Android devices suddenly couldn’t connect to the WiFi anymore. They reported “Connected, No Internet“. All other devices, connected via LAN or WiFi were just fine: PCs, FireTV Stick, other PIs – no issues. When I disabled the use of PiHole, they were able to connect again.

Continue reading How to fix: Android Connected, No Internet with Pi-Hole

Google Maps SDK does not show map in Release Build (works in Emulator)

I’ve been waisting some hours by hunting a stupid “bug”:
I am using Android Studio and was following the “Maps SDK for Android > Getting Started” guide. Of course I also ran into the issue of a wrong API key. But this was all solved by Googling and StackOverflow.

The map still showed up in the Emulator but NOT if deployed as stable release into the (beta) release channel to the PlayStore! LogCat was also silent … After a while I realized thetiny hint in AndroidStudio:

The light grey “(debug)” tells us that AndroidStudio placed the XML in “src/debug/res/values/” instead of “src/main/…”. Simply moving the file did the trick …

 

How to (re)schedule an alarm after an App upgrade in Android

In one of my Apps I am using alarms to schedule notifications.
Of course I also want to (re)schedule the alarm when the device is rebooted. Easy: Just set a BOOT_COMPLETED action in the intent-filter of the according schedule reciever:

<receiver android:name=".AlarmScheduleReceiver" android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>

The problem now just is that when the app is upgraded, your alarm will not be rescheduled! Not too much of a problem – if you know it! Just add another action into the intent-filter:

<action android:name="android.intent.action.PACKAGE_REPLACED" />

I was really lucky that a friend pointed that out when I added that feature to my app! Figuring this out just by getting user complaints that “the alarm sometimes doesn’t work” would not have been very funny!

I would have been pretty glad if the API docs would mention something like “hey, when you listen for BOOT_COMPLETE, you might consider listening for PACKAGE_REPLACED, too”. Well, that’s life.

Check internet connectivity in Android

When programming an Android App you sometimes want to check, if you are connected to the Internet.
The first thing that comes to mind is using the ConenctivityManager. Yet this solution has the problem that it only tells you that you are connected to .. something. With a WiFi connection this can mean, that you are connected to an access point. But it does not tell you that the access point is connected to something else!

Continue reading Check internet connectivity in Android

Take care when logging Exceptions!

Today I was facing some weird nullpointer exceptions (NPEs) in my Android App (Beta phase, luckily). Usually I catch exceptions like

try{ .. }catch(SomeException e){ 
   logger.info("A SomeException occured, but i got it.", e) 
}

Well in this part of the code I broke with my habit and wrote:

try{ .. }catch(SomeException e){ 
   logger.info("A SomeException occured, but i got it: "+e.getMessage(), e) 
}

And guess what. I experienced the expected exception, caught it (great) – and got a NPE somewhere in the Loggin framework. WTF?
After having a quick look at the Throwable API, I realized that getMessage() can indeed return null. And String+null produces null. So I nulled my logging message and passed this null reference right into the logging call – which produced the NPE in there. This was very annoying as I successfully caught the first exception – just to produce a susbsequent error during handling the first one.

Well, I immediately grepped my whole project for any strings like .getMessage() and checked for any other NPE traps.
Lesson learned today: carefully check the Api docs and be even more paranoid for NPEs.
Yet one question remains unanswered: Why on earth would one like to return null references in exceptions instead of empty strings?!

How to make Html Links in Android Text View work

The task itself is easy: You have a TextView which should show a clickable link to open a WebPage. As ususal, there are several ways to achieve the goal. The nasty thing is: if you mix them, they might no longer work. And also, some sometimes work, sometimes they don’t.

As it took me a little while to figure my final settings, I’ll note them here. A StackOverflow Post was a hint into a very good direction.

First, display the links as clickable links in the textview:

textView.setText(Html.fromHtml("Here is a <a href=\"http://www.Locked.de\">link</a>"));

Now there are two options:
Either make the link clickable programmatically by adding the following code:

textView.setMovementMethod(android.text.method.LinkMovementMethod.getInstance());

or add android:autoLink="web" to the according XML-element:

<TextView
android:id="@+id/myId"
android:autoLink="web"/>

If one of the options doesn’t work, try the other one, but don’t mix them. In one of my apps there are TextViews in two different activities with very similar setup. Yet, the android:autoLink="web" solution didn’t work in both TextViews whereas the setMovementMethod works in both. In the StackOverflow Post, some users also mention that both solutions didn’t work, and that android:linksClickable="true" was a solution.

My learning was: there are multiple ways to achieve the goal, but test it on each component separately as I do not yet completely trust the setMovementMethod way.

IllegalStateException: Content has been consumed

When working with Android or (to be more general) Apache HttpComponents, one should keep in mind that it depends on the HttpResponses (Api: Apache, Android) if they can be consumed multiple times or not. And if the response is not, then better triple check your code, what you’re doing.

I experiences the (very ugly) issue during the apparently simple task of reading the content of the response. )For ease of simplicity, I also use Apache commons-io, to read buffers etc.)

HttpResponse response = ...;
String content = IOUtils.toString(response.getEntity().entity.getContent());

Okay, how many possible Nullpointer Exceptions do you see? I didn’t care until I experienced the first one, so I made the code NPE safe:

HttpEntity entity = response.getEntity();
// entity can be null according to the docs!
if (entity != null) { 
    // The interface doesn't say that getContent() MUST return non-null
    InputStream stream = entity.getContent(); 
        if (stream != null) {
            tempContent = IOUtils.toString(entity.getContent());
        }
}

And suddenly I was faced with IllegalStateException: Content has been consumed. As I also did changes somewhere else, I assumed the error in some toString()-Methods that would read the content of the response during debugging. But as the error also showed up without debugging, I had a closer look to my “improvement”.

Well, the error was the call IOUtils.toString(entity.getContent()); which tried to re-aquire the Input Stream. But as I just aquired it two lines above for the null check, the content was already marked as consumed. So the (now hopefully) correct and robust code is:

HttpEntity entity = response.getEntity();
// entity can be null according to the docs!
if (entity != null) { 
    // The interface doesn't say that getContent() MUST return non-null
    InputStream stream = entity.getContent(); 
        if (stream != null) {
            tempContent = IOUtils.toString(<strong>stream</strong>);
        }
}

And the moral of the story

Be very carefull when reading HttpResponses! Also avoid pretty-printing the content in toString() – this might suddenly also consume your content. And good luck finding the point where you consume the content in such cases.

But .. why?! Please avoid returning null!

Yet I still wonder, why so many methods are allowed to return null instead of just an empty stream or something. All the Null-checks don’t make the code more readable. Some programmers might even be tempted to simply put an catch(NullPointerException e) around the part of

response.getEntity().entity.getContent()

. Nothing I’d really recommend but I could also understand if I’d see something in other code.

Android HTTP POST authentication error with Basic Auth

In one of my Android apps, a user should be able to push JSON data to the server. Of course this should only be allowed if the user is authorized by his credentials. For simplicity, I decided to use Basic Auth via HTTPS.

As I usually do not deal with Connectsions directly, I prefer to use the Apache Http classes to make life easier. So I used code like the following:

HttpParams httpParams = new BasicHttpParams();
HttpProtocolParams.setContentCharset(httpParams, HTTP.UTF_8);
HttpProtocolParams.setHttpElementCharset(httpParams, HTTP.UTF_8);
HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
client = new DefaultHttpClient(httpParams);
client.getCredentialsProvider().setCredentials(
    new AuthScope("localhost",80),
    new UsernamePasswordCredentials(username, password)
);

This was fine and worked in my local test environment and also in the live stage with GET requests. But when I started to POST data to the server I always got a “401 Unauthorized”. First I thought It’d be malformated JSON or encoding issues – but even with an empty string as payload I simply didn’t get through. Also the “same” POST request from the commandline using CURL worked like a charm! So it was very likely to be an issue with my handling of the Apache HTTP Lib. Stackoverflow also showed various people with the same problem. The proposed solution that came up several times was to manually set up the auth header. Not really the solution that I thought would be the greatest one.

After some more StackOverflow Posts and API crawling I found the very simple solution:

client.getCredentialsProvider().setCredentials(
   new AuthScope(AuthScope.ANY),
   new UsernamePasswordCredentials(username, password)

And yes, it was that easy! Just set the Auth scope correctly.

I’m just very surprised that I only encountered issues with the POST request. The very same configuration worked with a GET without problems. This was actually the point that made me sure that this part of the code was correct.